]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Fri, 8 Jul 2022 20:49:51 +0000 (16:49 -0400)
committerSasha Levin <sashal@kernel.org>
Fri, 8 Jul 2022 20:49:51 +0000 (16:49 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
143 files changed:
queue-5.15/alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch [new file with mode: 0644]
queue-5.15/alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch [new file with mode: 0644]
queue-5.15/asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch [new file with mode: 0644]
queue-5.15/asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch [new file with mode: 0644]
queue-5.15/asoc-rt5682-fix-deadlock-on-resume.patch [new file with mode: 0644]
queue-5.15/asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch [new file with mode: 0644]
queue-5.15/asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch [new file with mode: 0644]
queue-5.15/ath11k-add-hw_param-for-wakeup_mhi.patch [new file with mode: 0644]
queue-5.15/batman-adv-use-netif_rx.patch [new file with mode: 0644]
queue-5.15/block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch [new file with mode: 0644]
queue-5.15/block-only-mark-bio-as-tracked-if-it-really-is-track.patch [new file with mode: 0644]
queue-5.15/block-use-bdev_get_queue-in-bio.c.patch [new file with mode: 0644]
queue-5.15/bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch [new file with mode: 0644]
queue-5.15/bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch [new file with mode: 0644]
queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch [new file with mode: 0644]
queue-5.15/btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch [new file with mode: 0644]
queue-5.15/btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch [new file with mode: 0644]
queue-5.15/btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch [new file with mode: 0644]
queue-5.15/btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch [new file with mode: 0644]
queue-5.15/btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch [new file with mode: 0644]
queue-5.15/btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch [new file with mode: 0644]
queue-5.15/btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch [new file with mode: 0644]
queue-5.15/btrfs-remove-device-item-and-update-super-block-in-t.patch [new file with mode: 0644]
queue-5.15/btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch [new file with mode: 0644]
queue-5.15/btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch [new file with mode: 0644]
queue-5.15/btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch [new file with mode: 0644]
queue-5.15/btrfs-zoned-use-dedicated-lock-for-data-relocation.patch [new file with mode: 0644]
queue-5.15/bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch [new file with mode: 0644]
queue-5.15/bus-mhi-fix-pm_state-conversion-to-string.patch [new file with mode: 0644]
queue-5.15/clk-renesas-r9a07g044-update-multiplier-and-divider-.patch [new file with mode: 0644]
queue-5.15/compiler-attributes-add-__alloc_size-for-better-boun.patch [new file with mode: 0644]
queue-5.15/cxl-port-hold-port-reference-until-decoder-release.patch [new file with mode: 0644]
queue-5.15/dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch [new file with mode: 0644]
queue-5.15/drbd-add-error-handling-support-for-add_disk.patch [new file with mode: 0644]
queue-5.15/drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch [new file with mode: 0644]
queue-5.15/drbd-fix-double-free-problem-in-drbd_create_device.patch [new file with mode: 0644]
queue-5.15/drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch [new file with mode: 0644]
queue-5.15/drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch [new file with mode: 0644]
queue-5.15/drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch [new file with mode: 0644]
queue-5.15/drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch [new file with mode: 0644]
queue-5.15/drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch [new file with mode: 0644]
queue-5.15/drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch [new file with mode: 0644]
queue-5.15/drm-amdgpu-fix-rejecting-tahiti-gpus.patch [new file with mode: 0644]
queue-5.15/drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch [new file with mode: 0644]
queue-5.15/drm-i915-disable-bonding-on-gen12-platforms.patch [new file with mode: 0644]
queue-5.15/drm-i915-fix-a-race-between-vma-object-destruction-a.patch [new file with mode: 0644]
queue-5.15/drm-i915-gt-register-the-migrate-contexts-with-their.patch [new file with mode: 0644]
queue-5.15/drm-i915-replace-the-unconditional-clflush-with-drm_.patch [new file with mode: 0644]
queue-5.15/drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch [new file with mode: 0644]
queue-5.15/drm-mediatek-add-vblank-register-unregister-callback.patch [new file with mode: 0644]
queue-5.15/drm-mediatek-detect-cmdq-execution-timeout.patch [new file with mode: 0644]
queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch [new file with mode: 0644]
queue-5.15/drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch [new file with mode: 0644]
queue-5.15/drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch [new file with mode: 0644]
queue-5.15/drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch [new file with mode: 0644]
queue-5.15/drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch [new file with mode: 0644]
queue-5.15/drm-msm-properly-add-and-remove-internal-bridges.patch [new file with mode: 0644]
queue-5.15/dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch [new file with mode: 0644]
queue-5.15/dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch [new file with mode: 0644]
queue-5.15/gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch [new file with mode: 0644]
queue-5.15/ibmvnic-allow-queueing-resets-during-probe.patch [new file with mode: 0644]
queue-5.15/ibmvnic-clear-fop-when-retrying-probe.patch [new file with mode: 0644]
queue-5.15/ibmvnic-init-init_done_rc-earlier.patch [new file with mode: 0644]
queue-5.15/iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch [new file with mode: 0644]
queue-5.15/input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch [new file with mode: 0644]
queue-5.15/input-goodix-add-a-goodix.h-header-file.patch [new file with mode: 0644]
queue-5.15/input-goodix-change-goodix_i2c_write-len-parameter-t.patch [new file with mode: 0644]
queue-5.15/input-goodix-refactor-reset-handling.patch [new file with mode: 0644]
queue-5.15/input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch [new file with mode: 0644]
queue-5.15/io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch [new file with mode: 0644]
queue-5.15/io_uring-ensure-that-fsnotify-is-always-called.patch [new file with mode: 0644]
queue-5.15/irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch [new file with mode: 0644]
queue-5.15/kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch [new file with mode: 0644]
queue-5.15/kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch [new file with mode: 0644]
queue-5.15/kvm-s390x-fix-sck-locking.patch [new file with mode: 0644]
queue-5.15/kvm-use-__vcalloc-for-very-large-allocations.patch [new file with mode: 0644]
queue-5.15/kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch [new file with mode: 0644]
queue-5.15/kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch [new file with mode: 0644]
queue-5.15/media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch [new file with mode: 0644]
queue-5.15/media-ir_toy-prevent-device-from-hanging-during-tran.patch [new file with mode: 0644]
queue-5.15/media-omap3isp-use-struct_group-for-memcpy-region.patch [new file with mode: 0644]
queue-5.15/memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch [new file with mode: 0644]
queue-5.15/mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch [new file with mode: 0644]
queue-5.15/mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch [new file with mode: 0644]
queue-5.15/mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch [new file with mode: 0644]
queue-5.15/mm-memory-failure.c-fix-race-with-changing-page-comp.patch [new file with mode: 0644]
queue-5.15/mm-vmalloc-introduce-array-allocation-functions.patch [new file with mode: 0644]
queue-5.15/module-change-to-print-useful-messages-from-elf_vali.patch [new file with mode: 0644]
queue-5.15/module-fix-e_shstrndx-.sh_size-0-oob-access.patch [new file with mode: 0644]
queue-5.15/mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch [new file with mode: 0644]
queue-5.15/mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch [new file with mode: 0644]
queue-5.15/mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch [new file with mode: 0644]
queue-5.15/mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch [new file with mode: 0644]
queue-5.15/mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch [new file with mode: 0644]
queue-5.15/mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch [new file with mode: 0644]
queue-5.15/net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch [new file with mode: 0644]
queue-5.15/net-mlx5e-split-actions_match_supported-into-a-sub-f.patch [new file with mode: 0644]
queue-5.15/net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch [new file with mode: 0644]
queue-5.15/net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch [new file with mode: 0644]
queue-5.15/netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch [new file with mode: 0644]
queue-5.15/netfilter-nft_payload-don-t-allow-th-access-for-frag.patch [new file with mode: 0644]
queue-5.15/netfilter-nft_payload-support-for-inner-header-match.patch [new file with mode: 0644]
queue-5.15/nfsd-commit-operations-must-not-return-nfs-err_inval.patch [new file with mode: 0644]
queue-5.15/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch [new file with mode: 0644]
queue-5.15/pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch [new file with mode: 0644]
queue-5.15/pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch [new file with mode: 0644]
queue-5.15/platform-x86-wmi-fix-driver-notify-vs-probe-race.patch [new file with mode: 0644]
queue-5.15/platform-x86-wmi-introduce-helper-to-convert-driver-.patch [new file with mode: 0644]
queue-5.15/platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch [new file with mode: 0644]
queue-5.15/powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch [new file with mode: 0644]
queue-5.15/powerpc-flexible-gpr-range-save-restore-macros.patch [new file with mode: 0644]
queue-5.15/powerpc-tm-fix-more-userspace-r13-corruption.patch [new file with mode: 0644]
queue-5.15/powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch [new file with mode: 0644]
queue-5.15/powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch [new file with mode: 0644]
queue-5.15/powerpc-vdso-remove-cvdso_call_time-macro.patch [new file with mode: 0644]
queue-5.15/qed-improve-the-stack-space-of-filter_config.patch [new file with mode: 0644]
queue-5.15/risc-v-defconfigs-set-config_fb-y-for-fb-console.patch [new file with mode: 0644]
queue-5.15/riscv-defconfig-enable-drm_nouveau.patch [new file with mode: 0644]
queue-5.15/riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch [new file with mode: 0644]
queue-5.15/rxrpc-fix-locking-issue.patch [new file with mode: 0644]
queue-5.15/s390-boot-allocate-amode31-section-in-decompressor.patch [new file with mode: 0644]
queue-5.15/s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch [new file with mode: 0644]
queue-5.15/s390-setup-use-physical-pointers-for-memblock_reserv.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch [new file with mode: 0644]
queue-5.15/serial-8250_mtk-make-sure-to-select-the-right-featur.patch [new file with mode: 0644]
queue-5.15/serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/stddef-introduce-declare_flex_array-helper.patch [new file with mode: 0644]
queue-5.15/stddef-introduce-struct_group-helper-macro.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-fix-frame-reception-handling.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-fix-missing-update-of-modem-controls-after.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch [new file with mode: 0644]
queue-5.15/tty-n_gsm-save-dlci-address-open-status-when-config-.patch [new file with mode: 0644]
queue-5.15/uapi-linux-stddef.h-add-include-guards.patch [new file with mode: 0644]
queue-5.15/vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch [new file with mode: 0644]
queue-5.15/virtio-blk-avoid-preallocating-big-sgl-for-data.patch [new file with mode: 0644]

diff --git a/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch b/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch
new file mode 100644 (file)
index 0000000..83d8eec
--- /dev/null
@@ -0,0 +1,42 @@
+From 70d147f7a2a0e7ccf2c50d96f36c4490166bd763 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 18 Apr 2022 15:16:12 +0200
+Subject: ALSA: usb-audio: add mapping for MSI MAG X570S Torpedo MAX.
+
+From: Maurizio Avogadro <mavoga@gmail.com>
+
+[ Upstream commit 4ddef9c4d70aae0c9029bdec7c3f7f1c1c51ff8c ]
+
+The USB audio device 0db0:a073 based on the Realtek ALC4080 chipset
+exposes all playback volume controls as "PCM". This makes
+distinguishing the individual functions hard.
+The mapping already adopted for device 0db0:419c based on the same
+chipset fixes the issue, apply it for this device too.
+
+Signed-off-by: Maurizio Avogadro <mavoga@gmail.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/Yl1ykPaGgsFf3SnW@ryzen
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/mixer_maps.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
+index 64fdca76b40e..997425ef0a29 100644
+--- a/sound/usb/mixer_maps.c
++++ b/sound/usb/mixer_maps.c
+@@ -586,6 +586,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
+               .id = USB_ID(0x0db0, 0x419c),
+               .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map,
+       },
++      {       /* MSI MAG X570S Torpedo Max */
++              .id = USB_ID(0x0db0, 0xa073),
++              .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map,
++      },
+       {       /* MSI TRX40 */
+               .id = USB_ID(0x0db0, 0x543d),
+               .map = trx40_mobo_map,
+-- 
+2.35.1
+
diff --git a/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch b/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch
new file mode 100644 (file)
index 0000000..ea121ee
--- /dev/null
@@ -0,0 +1,62 @@
+From b63fa9e91ceffba521c0fee09d1d2cbd80fbffe8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Jan 2022 15:02:57 +0100
+Subject: ALSA: usb-audio: add mapping for MSI MPG X570S Carbon Max Wifi.
+
+From: Johannes Schickel <lordhoto@gmail.com>
+
+[ Upstream commit 5762f980ca10dcfe5eead7c40d1c34cae61f409b ]
+
+The USB audio device 0db0:419c based on the Realtek ALC4080 chip exposes
+all playback volume controls as "PCM". This is makes distinguishing the
+individual functions hard.
+
+The added mapping distinguishes all playback volume controls as their
+respective function:
+ - Speaker              - for back panel output
+ - Frontpanel Headphone - for front panel output
+ - IEC958               - for digital output on the back panel
+
+This clarifies the individual volume control functions for users.
+
+Signed-off-by: Johannes Schickel <lordhoto@gmail.com>
+Link: https://lore.kernel.org/r/20220115140257.8751-1-lordhoto@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/mixer_maps.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
+index 6ffd23f2ee65..64fdca76b40e 100644
+--- a/sound/usb/mixer_maps.c
++++ b/sound/usb/mixer_maps.c
+@@ -423,6 +423,14 @@ static const struct usbmix_name_map aorus_master_alc1220vb_map[] = {
+       {}
+ };
++/* MSI MPG X570S Carbon Max Wifi with ALC4080  */
++static const struct usbmix_name_map msi_mpg_x570s_carbon_max_wifi_alc4080_map[] = {
++      { 29, "Speaker Playback" },
++      { 30, "Front Headphone Playback" },
++      { 32, "IEC958 Playback" },
++      {}
++};
++
+ /*
+  * Control map entries
+  */
+@@ -574,6 +582,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
+               .map = trx40_mobo_map,
+               .connector_map = trx40_mobo_connector_map,
+       },
++      {       /* MSI MPG X570S Carbon Max Wifi */
++              .id = USB_ID(0x0db0, 0x419c),
++              .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map,
++      },
+       {       /* MSI TRX40 */
+               .id = USB_ID(0x0db0, 0x543d),
+               .map = trx40_mobo_map,
+-- 
+2.35.1
+
diff --git a/queue-5.15/asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch b/queue-5.15/asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch
new file mode 100644 (file)
index 0000000..2638f42
--- /dev/null
@@ -0,0 +1,66 @@
+From a1d66cbea10efc22a7dab5b80c5f03ef93b3357b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Nov 2021 17:54:49 +0800
+Subject: ASoC: rt5682: Avoid the unexpected IRQ event during going to suspend
+
+From: Derek Fang <derek.fang@realtek.com>
+
+[ Upstream commit a3774a2a6544a7a4a85186e768afc07044aa507f ]
+
+When the system suspends, the codec driver will set SAR to
+power saving mode if a headset is plugged in.
+There is a chance to generate an unexpected IRQ, and leads to
+issues after resuming such as noise from OMTP type headsets.
+
+Signed-off-by: Derek Fang <derek.fang@realtek.com>
+Link: https://lore.kernel.org/r/20211109095450.12950-1-derek.fang@realtek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt5682.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index 6ad3159eceb9..949b5638db29 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -48,6 +48,7 @@ static const struct reg_sequence patch_list[] = {
+       {RT5682_SAR_IL_CMD_6, 0x0110},
+       {RT5682_CHARGE_PUMP_1, 0x0210},
+       {RT5682_HP_LOGIC_CTRL_2, 0x0007},
++      {RT5682_SAR_IL_CMD_2, 0xac00},
+ };
+ void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
+@@ -2969,9 +2970,6 @@ static int rt5682_suspend(struct snd_soc_component *component)
+       cancel_delayed_work_sync(&rt5682->jack_detect_work);
+       cancel_delayed_work_sync(&rt5682->jd_check_work);
+       if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
+-              snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+-                      RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+-                      RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
+               val = snd_soc_component_read(component,
+                               RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+@@ -2993,10 +2991,15 @@ static int rt5682_suspend(struct snd_soc_component *component)
+               /* enter SAR ADC power saving mode */
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+                       RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK |
+-                      RT5682_SAR_BUTDET_RST_MASK | RT5682_SAR_SEL_MB1_MB2_MASK, 0);
++                      RT5682_SAR_SEL_MB1_MB2_MASK, 0);
++              usleep_range(5000, 6000);
++              snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
++                      RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
++                      RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
++              usleep_range(10000, 12000);
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+-                      RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_BUTDET_RST_MASK,
+-                      RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV | RT5682_SAR_BUTDET_RST_NORMAL);
++                      RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK,
++                      RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV);
+       }
+       regcache_cache_only(rt5682->regmap, true);
+-- 
+2.35.1
+
diff --git a/queue-5.15/asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch b/queue-5.15/asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch
new file mode 100644 (file)
index 0000000..3d5ac7f
--- /dev/null
@@ -0,0 +1,60 @@
+From 15f05c1212d9a693668dd609552053578031b19b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 27 Mar 2022 16:10:02 +0800
+Subject: ASoC: rt5682: fix an incorrect NULL check on list iterator
+
+From: Xiaomeng Tong <xiam0nd.tong@gmail.com>
+
+[ Upstream commit c8618d65007ba68d7891130642d73e89372101e8 ]
+
+The bug is here:
+       if (!dai) {
+
+The list iterator value 'dai' will *always* be set and non-NULL
+by for_each_component_dais(), so it is incorrect to assume that
+the iterator value will be NULL if the list is empty or no element
+is found (In fact, it will be a bogus pointer to an invalid struct
+object containing the HEAD). Otherwise it will bypass the check
+'if (!dai) {' (never call dev_err() and never return -ENODEV;)
+and lead to invalid memory access lately when calling
+'rt5682_set_bclk1_ratio(dai, factor);'.
+
+To fix the bug, just return rt5682_set_bclk1_ratio(dai, factor);
+when found the 'dai', otherwise dev_err() and return -ENODEV;
+
+Cc: stable@vger.kernel.org
+Fixes: ebbfabc16d23d ("ASoC: rt5682: Add CCF usage for providing I2S clks")
+Signed-off-by: Xiaomeng Tong <xiam0nd.tong@gmail.com>
+Link: https://lore.kernel.org/r/20220327081002.12684-1-xiam0nd.tong@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt5682.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index 80d199843b8c..8a9e1a4fa03e 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -2822,14 +2822,11 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
+       for_each_component_dais(component, dai)
+               if (dai->id == RT5682_AIF1)
+-                      break;
+-      if (!dai) {
+-              dev_err(rt5682->i2c_dev, "dai %d not found in component\n",
+-                      RT5682_AIF1);
+-              return -ENODEV;
+-      }
++                      return rt5682_set_bclk1_ratio(dai, factor);
+-      return rt5682_set_bclk1_ratio(dai, factor);
++      dev_err(rt5682->i2c_dev, "dai %d not found in component\n",
++              RT5682_AIF1);
++      return -ENODEV;
+ }
+ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = {
+-- 
+2.35.1
+
diff --git a/queue-5.15/asoc-rt5682-fix-deadlock-on-resume.patch b/queue-5.15/asoc-rt5682-fix-deadlock-on-resume.patch
new file mode 100644 (file)
index 0000000..d8b24b5
--- /dev/null
@@ -0,0 +1,200 @@
+From 24475d1fc560af3cb3e0f6796b2933691ae2eda5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Jan 2022 12:03:25 +0200
+Subject: ASoC: rt5682: Fix deadlock on resume
+
+From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+
+[ Upstream commit 4045daf0fa87846a27f56329fddad2deeb5ca354 ]
+
+On resume from suspend the following chain of events can happen:
+A rt5682_resume() -> mod_delayed_work() for jack_detect_work
+B DAPM sequence starts ( DAPM is locked now)
+
+A1. rt5682_jack_detect_handler() scheduled
+ - Takes both jdet_mutex and calibrate_mutex
+ - Calls in to rt5682_headset_detect() which tries to take DAPM lock, it
+   starts to wait for it as B path took it already.
+B1. DAPM sequence reaches the "HP Amp", rt5682_hp_event() tries to take
+    the jdet_mutex, but it is locked in A1, so it waits.
+
+Deadlock.
+
+To solve the deadlock, drop the jdet_mutex, use the jack_detect_work to do
+the jack removal handling, move the dapm lock up one level to protect the
+most of the rt5682_jack_detect_handler(), but not the jack reporting as it
+might trigger a DAPM sequence.
+The rt5682_headset_detect() can be changed to static as well.
+
+Fixes: 8deb34a90f063 ("ASoC: rt5682: fix the wrong jack type detected")
+Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+Link: https://lore.kernel.org/r/20220126100325.16513-1-peter.ujfalusi@linux.intel.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt5682-i2c.c | 15 ++++-----------
+ sound/soc/codecs/rt5682.c     | 24 ++++++++----------------
+ sound/soc/codecs/rt5682.h     |  2 --
+ 3 files changed, 12 insertions(+), 29 deletions(-)
+
+diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
+index b17c14b8b36e..74a1fee071dd 100644
+--- a/sound/soc/codecs/rt5682-i2c.c
++++ b/sound/soc/codecs/rt5682-i2c.c
+@@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work)
+       struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
+               jd_check_work.work);
+-      if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
+-              & RT5682_JDH_RS_MASK) {
++      if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK)
+               /* jack out */
+-              rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+-
+-              snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+-                      SND_JACK_HEADSET |
+-                      SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+-                      SND_JACK_BTN_2 | SND_JACK_BTN_3);
+-      } else {
++              mod_delayed_work(system_power_efficient_wq,
++                               &rt5682->jack_detect_work, 0);
++      else
+               schedule_delayed_work(&rt5682->jd_check_work, 500);
+-      }
+ }
+ static irqreturn_t rt5682_irq(int irq, void *data)
+@@ -196,7 +190,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
+       }
+       mutex_init(&rt5682->calibrate_mutex);
+-      mutex_init(&rt5682->jdet_mutex);
+       rt5682_calibrate(rt5682);
+       rt5682_apply_patch_list(rt5682, &i2c->dev);
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index d470b9189768..1cd59e166cce 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -922,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
+  *
+  * Returns detect status.
+  */
+-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
++static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+ {
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       struct snd_soc_dapm_context *dapm = &component->dapm;
+       unsigned int val, count;
+       if (jack_insert) {
+-              snd_soc_dapm_mutex_lock(dapm);
+-
+               snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
+                       RT5682_PWR_VREF2 | RT5682_PWR_MB,
+                       RT5682_PWR_VREF2 | RT5682_PWR_MB);
+@@ -981,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+               snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
+                       RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
+                       RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
+-
+-              snd_soc_dapm_mutex_unlock(dapm);
+       } else {
+               rt5682_enable_push_button_irq(component, false);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+@@ -1011,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+       dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
+       return rt5682->jack_type;
+ }
+-EXPORT_SYMBOL_GPL(rt5682_headset_detect);
+ static int rt5682_set_jack_detect(struct snd_soc_component *component,
+               struct snd_soc_jack *hs_jack, void *data)
+@@ -1094,6 +1089,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+ {
+       struct rt5682_priv *rt5682 =
+               container_of(work, struct rt5682_priv, jack_detect_work.work);
++      struct snd_soc_dapm_context *dapm;
+       int val, btn_type;
+       if (!rt5682->component || !rt5682->component->card ||
+@@ -1104,7 +1100,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+               return;
+       }
+-      mutex_lock(&rt5682->jdet_mutex);
++      dapm = snd_soc_component_get_dapm(rt5682->component);
++
++      snd_soc_dapm_mutex_lock(dapm);
+       mutex_lock(&rt5682->calibrate_mutex);
+       val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
+@@ -1164,6 +1162,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+               rt5682->irq_work_delay_time = 50;
+       }
++      mutex_unlock(&rt5682->calibrate_mutex);
++      snd_soc_dapm_mutex_unlock(dapm);
++
+       snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+               SND_JACK_HEADSET |
+               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+@@ -1176,9 +1177,6 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+               else
+                       cancel_delayed_work_sync(&rt5682->jd_check_work);
+       }
+-
+-      mutex_unlock(&rt5682->calibrate_mutex);
+-      mutex_unlock(&rt5682->jdet_mutex);
+ }
+ EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
+@@ -1528,7 +1526,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+ {
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+-      struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+@@ -1540,17 +1537,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+                       RT5682_DEPOP_1, 0x60, 0x60);
+               snd_soc_component_update_bits(component,
+                       RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
+-
+-              mutex_lock(&rt5682->jdet_mutex);
+-
+               snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
+                       RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
+                       RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
+               usleep_range(5000, 10000);
+               snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
+                       RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
+-
+-              mutex_unlock(&rt5682->jdet_mutex);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
+index f866d207d1bd..539a9fe26294 100644
+--- a/sound/soc/codecs/rt5682.h
++++ b/sound/soc/codecs/rt5682.h
+@@ -1462,7 +1462,6 @@ struct rt5682_priv {
+       int jack_type;
+       int irq_work_delay_time;
+-      struct mutex jdet_mutex;
+ };
+ extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
+@@ -1472,7 +1471,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+ void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
+-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
+ void rt5682_jack_detect_handler(struct work_struct *work);
+ bool rt5682_volatile_register(struct device *dev, unsigned int reg);
+-- 
+2.35.1
+
diff --git a/queue-5.15/asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch b/queue-5.15/asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch
new file mode 100644 (file)
index 0000000..811f5dd
--- /dev/null
@@ -0,0 +1,301 @@
+From 75edcb0cd088c3241d04806301160d9fb537c70b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 29 Sep 2021 13:43:44 +0800
+Subject: ASoC: rt5682: move clk related code to rt5682_i2c_probe
+
+From: Jack Yu <jack.yu@realtek.com>
+
+[ Upstream commit 57589f82762e40bdaa975d840fa2bc5157b5be95 ]
+
+The DAI clock is only used in I2S mode, to make it clear
+and to fix clock resource release issue, we move CCF clock
+related code to rt5682_i2c_probe to fix clock
+register/unregister issue.
+
+Signed-off-by: Jack Yu <jack.yu@realtek.com>
+Link: https://lore.kernel.org/r/20210929054344.12112-1-jack.yu@realtek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt5682-i2c.c | 22 +++++++++++
+ sound/soc/codecs/rt5682.c     | 70 +++++++++++++----------------------
+ sound/soc/codecs/rt5682.h     |  3 ++
+ 3 files changed, 51 insertions(+), 44 deletions(-)
+
+diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
+index 74a1fee071dd..3d2d7c9ce66d 100644
+--- a/sound/soc/codecs/rt5682-i2c.c
++++ b/sound/soc/codecs/rt5682-i2c.c
+@@ -133,6 +133,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
+       i2c_set_clientdata(i2c, rt5682);
++      rt5682->i2c_dev = &i2c->dev;
++
+       rt5682->pdata = i2s_default_platform_data;
+       if (pdata)
+@@ -270,6 +272,26 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
+                       dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+       }
++#ifdef CONFIG_COMMON_CLK
++      /* Check if MCLK provided */
++      rt5682->mclk = devm_clk_get(&i2c->dev, "mclk");
++      if (IS_ERR(rt5682->mclk)) {
++              if (PTR_ERR(rt5682->mclk) != -ENOENT) {
++                      ret = PTR_ERR(rt5682->mclk);
++                      return ret;
++              }
++              rt5682->mclk = NULL;
++      }
++
++      /* Register CCF DAI clock control */
++      ret = rt5682_register_dai_clks(rt5682);
++      if (ret)
++              return ret;
++
++      /* Initial setup for CCF */
++      rt5682->lrck[RT5682_AIF1] = 48000;
++#endif
++
+       return devm_snd_soc_register_component(&i2c->dev,
+                                              &rt5682_soc_component_dev,
+                                              rt5682_dai, ARRAY_SIZE(rt5682_dai));
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index 1cd59e166cce..80d199843b8c 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -2562,7 +2562,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component,
+ static bool rt5682_clk_check(struct rt5682_priv *rt5682)
+ {
+       if (!rt5682->master[RT5682_AIF1]) {
+-              dev_dbg(rt5682->component->dev, "sysclk/dai not set correctly\n");
++              dev_dbg(rt5682->i2c_dev, "sysclk/dai not set correctly\n");
+               return false;
+       }
+       return true;
+@@ -2573,13 +2573,15 @@ static int rt5682_wclk_prepare(struct clk_hw *hw)
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
+-      struct snd_soc_dapm_context *dapm =
+-                      snd_soc_component_get_dapm(component);
++      struct snd_soc_component *component;
++      struct snd_soc_dapm_context *dapm;
+       if (!rt5682_clk_check(rt5682))
+               return -EINVAL;
++      component = rt5682->component;
++      dapm = snd_soc_component_get_dapm(component);
++
+       snd_soc_dapm_mutex_lock(dapm);
+       snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
+@@ -2609,13 +2611,15 @@ static void rt5682_wclk_unprepare(struct clk_hw *hw)
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
+-      struct snd_soc_dapm_context *dapm =
+-                      snd_soc_component_get_dapm(component);
++      struct snd_soc_component *component;
++      struct snd_soc_dapm_context *dapm;
+       if (!rt5682_clk_check(rt5682))
+               return;
++      component = rt5682->component;
++      dapm = snd_soc_component_get_dapm(component);
++
+       snd_soc_dapm_mutex_lock(dapm);
+       snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
+@@ -2639,7 +2643,6 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw,
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
+       const char * const clk_name = clk_hw_get_name(hw);
+       if (!rt5682_clk_check(rt5682))
+@@ -2649,7 +2652,7 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw,
+        */
+       if (rt5682->lrck[RT5682_AIF1] != CLK_48 &&
+           rt5682->lrck[RT5682_AIF1] != CLK_44) {
+-              dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n",
++              dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n",
+                       __func__, clk_name, CLK_44, CLK_48);
+               return 0;
+       }
+@@ -2663,7 +2666,6 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
+       const char * const clk_name = clk_hw_get_name(hw);
+       if (!rt5682_clk_check(rt5682))
+@@ -2673,7 +2675,7 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
+        * It will force to 48kHz if not both.
+        */
+       if (rate != CLK_48 && rate != CLK_44) {
+-              dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n",
++              dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n",
+                       __func__, clk_name, CLK_44, CLK_48);
+               rate = CLK_48;
+       }
+@@ -2687,7 +2689,7 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
++      struct snd_soc_component *component;
+       struct clk_hw *parent_hw;
+       const char * const clk_name = clk_hw_get_name(hw);
+       int pre_div;
+@@ -2696,6 +2698,8 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
+       if (!rt5682_clk_check(rt5682))
+               return -EINVAL;
++      component = rt5682->component;
++
+       /*
+        * Whether the wclk's parent clk (mclk) exists or not, please ensure
+        * it is fixed or set to 48MHz before setting wclk rate. It's a
+@@ -2705,12 +2709,12 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
+        */
+       parent_hw = clk_hw_get_parent(hw);
+       if (!parent_hw)
+-              dev_warn(component->dev,
++              dev_warn(rt5682->i2c_dev,
+                       "Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n",
+                       CLK_PLL2_FIN);
+       if (parent_rate != CLK_PLL2_FIN)
+-              dev_warn(component->dev, "clk %s only support %d Hz input\n",
++              dev_warn(rt5682->i2c_dev, "clk %s only support %d Hz input\n",
+                       clk_name, CLK_PLL2_FIN);
+       /*
+@@ -2742,10 +2746,9 @@ static unsigned long rt5682_bclk_recalc_rate(struct clk_hw *hw,
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_BCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
+       unsigned int bclks_per_wclk;
+-      bclks_per_wclk = snd_soc_component_read(component, RT5682_TDM_TCON_CTRL);
++      regmap_read(rt5682->regmap, RT5682_TDM_TCON_CTRL, &bclks_per_wclk);
+       switch (bclks_per_wclk & RT5682_TDM_BCLK_MS1_MASK) {
+       case RT5682_TDM_BCLK_MS1_256:
+@@ -2806,20 +2809,22 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
+       struct rt5682_priv *rt5682 =
+               container_of(hw, struct rt5682_priv,
+                            dai_clks_hw[RT5682_DAI_BCLK_IDX]);
+-      struct snd_soc_component *component = rt5682->component;
++      struct snd_soc_component *component;
+       struct snd_soc_dai *dai;
+       unsigned long factor;
+       if (!rt5682_clk_check(rt5682))
+               return -EINVAL;
++      component = rt5682->component;
++
+       factor = rt5682_bclk_get_factor(rate, parent_rate);
+       for_each_component_dais(component, dai)
+               if (dai->id == RT5682_AIF1)
+                       break;
+       if (!dai) {
+-              dev_err(component->dev, "dai %d not found in component\n",
++              dev_err(rt5682->i2c_dev, "dai %d not found in component\n",
+                       RT5682_AIF1);
+               return -ENODEV;
+       }
+@@ -2842,10 +2847,9 @@ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = {
+       },
+ };
+-static int rt5682_register_dai_clks(struct snd_soc_component *component)
++int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
+ {
+-      struct device *dev = component->dev;
+-      struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
++      struct device *dev = rt5682->i2c_dev;
+       struct rt5682_platform_data *pdata = &rt5682->pdata;
+       struct clk_hw *dai_clk_hw;
+       int i, ret;
+@@ -2905,6 +2909,7 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component)
+       return 0;
+ }
++EXPORT_SYMBOL_GPL(rt5682_register_dai_clks);
+ #endif /* CONFIG_COMMON_CLK */
+ static int rt5682_probe(struct snd_soc_component *component)
+@@ -2914,9 +2919,6 @@ static int rt5682_probe(struct snd_soc_component *component)
+       unsigned long time;
+       struct snd_soc_dapm_context *dapm = &component->dapm;
+-#ifdef CONFIG_COMMON_CLK
+-      int ret;
+-#endif
+       rt5682->component = component;
+       if (rt5682->is_sdw) {
+@@ -2928,26 +2930,6 @@ static int rt5682_probe(struct snd_soc_component *component)
+                       dev_err(&slave->dev, "Initialization not complete, timed out\n");
+                       return -ETIMEDOUT;
+               }
+-      } else {
+-#ifdef CONFIG_COMMON_CLK
+-              /* Check if MCLK provided */
+-              rt5682->mclk = devm_clk_get(component->dev, "mclk");
+-              if (IS_ERR(rt5682->mclk)) {
+-                      if (PTR_ERR(rt5682->mclk) != -ENOENT) {
+-                              ret = PTR_ERR(rt5682->mclk);
+-                              return ret;
+-                      }
+-                      rt5682->mclk = NULL;
+-              }
+-
+-              /* Register CCF DAI clock control */
+-              ret = rt5682_register_dai_clks(component);
+-              if (ret)
+-                      return ret;
+-
+-              /* Initial setup for CCF */
+-              rt5682->lrck[RT5682_AIF1] = CLK_48;
+-#endif
+       }
+       snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
+index 539a9fe26294..52ff0d9c36c5 100644
+--- a/sound/soc/codecs/rt5682.h
++++ b/sound/soc/codecs/rt5682.h
+@@ -1428,6 +1428,7 @@ enum {
+ struct rt5682_priv {
+       struct snd_soc_component *component;
++      struct device *i2c_dev;
+       struct rt5682_platform_data pdata;
+       struct regmap *regmap;
+       struct regmap *sdw_regmap;
+@@ -1481,6 +1482,8 @@ void rt5682_calibrate(struct rt5682_priv *rt5682);
+ void rt5682_reset(struct rt5682_priv *rt5682);
+ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev);
++int rt5682_register_dai_clks(struct rt5682_priv *rt5682);
++
+ #define RT5682_REG_NUM 318
+ extern const struct reg_default rt5682_reg[RT5682_REG_NUM];
+-- 
+2.35.1
+
diff --git a/queue-5.15/asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch b/queue-5.15/asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch
new file mode 100644 (file)
index 0000000..d39885f
--- /dev/null
@@ -0,0 +1,157 @@
+From 2cf86625feb194848dabe1ba576373078aaf7d17 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Nov 2021 17:54:50 +0800
+Subject: ASoC: rt5682: Re-detect the combo jack after resuming
+
+From: Derek Fang <derek.fang@realtek.com>
+
+[ Upstream commit 2cd9b0ef82d936623d789bb3fbb6fcf52c500367 ]
+
+Sometimes, end-users change the jack type under suspending,
+so it needs to re-detect the combo jack type after resuming to
+avoid any unexpected behaviors.
+
+Signed-off-by: Derek Fang <derek.fang@realtek.com>
+Link: https://lore.kernel.org/r/20211109095450.12950-2-derek.fang@realtek.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/rt5682-i2c.c |  1 +
+ sound/soc/codecs/rt5682.c     | 23 ++++++++++++++++++++---
+ sound/soc/codecs/rt5682.h     |  1 +
+ 3 files changed, 22 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
+index b9d5d7a0975b..b17c14b8b36e 100644
+--- a/sound/soc/codecs/rt5682-i2c.c
++++ b/sound/soc/codecs/rt5682-i2c.c
+@@ -196,6 +196,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
+       }
+       mutex_init(&rt5682->calibrate_mutex);
++      mutex_init(&rt5682->jdet_mutex);
+       rt5682_calibrate(rt5682);
+       rt5682_apply_patch_list(rt5682, &i2c->dev);
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index 949b5638db29..d470b9189768 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -49,6 +49,7 @@ static const struct reg_sequence patch_list[] = {
+       {RT5682_CHARGE_PUMP_1, 0x0210},
+       {RT5682_HP_LOGIC_CTRL_2, 0x0007},
+       {RT5682_SAR_IL_CMD_2, 0xac00},
++      {RT5682_CBJ_CTRL_7, 0x0104},
+ };
+ void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
+@@ -943,6 +944,10 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+               snd_soc_component_update_bits(component,
+                       RT5682_HP_CHARGE_PUMP_1,
+                       RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
++              rt5682_enable_push_button_irq(component, false);
++              snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
++                      RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW);
++              usleep_range(55000, 60000);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
+@@ -1099,6 +1104,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+               return;
+       }
++      mutex_lock(&rt5682->jdet_mutex);
+       mutex_lock(&rt5682->calibrate_mutex);
+       val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
+@@ -1172,6 +1178,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+       }
+       mutex_unlock(&rt5682->calibrate_mutex);
++      mutex_unlock(&rt5682->jdet_mutex);
+ }
+ EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
+@@ -1521,6 +1528,7 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+ {
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
++      struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+@@ -1532,12 +1540,17 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+                       RT5682_DEPOP_1, 0x60, 0x60);
+               snd_soc_component_update_bits(component,
+                       RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
++
++              mutex_lock(&rt5682->jdet_mutex);
++
+               snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
+                       RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
+                       RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
+               usleep_range(5000, 10000);
+               snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
+                       RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
++
++              mutex_unlock(&rt5682->jdet_mutex);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+@@ -2969,7 +2982,7 @@ static int rt5682_suspend(struct snd_soc_component *component)
+       cancel_delayed_work_sync(&rt5682->jack_detect_work);
+       cancel_delayed_work_sync(&rt5682->jd_check_work);
+-      if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
++      if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
+               val = snd_soc_component_read(component,
+                               RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+@@ -3000,6 +3013,8 @@ static int rt5682_suspend(struct snd_soc_component *component)
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+                       RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK,
+                       RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV);
++              snd_soc_component_update_bits(component, RT5682_HP_CHARGE_PUMP_1,
++                      RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
+       }
+       regcache_cache_only(rt5682->regmap, true);
+@@ -3017,10 +3032,11 @@ static int rt5682_resume(struct snd_soc_component *component)
+       regcache_cache_only(rt5682->regmap, false);
+       regcache_sync(rt5682->regmap);
+-      if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
++      if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
+               snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+                       RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_SEL_MB1_MB2_MASK,
+                       RT5682_SAR_BUTDET_POW_NORM | RT5682_SAR_SEL_MB1_MB2_AUTO);
++              usleep_range(5000, 6000);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+                       RT5682_CTRL_MB1_FSM | RT5682_CTRL_MB2_FSM);
+@@ -3028,8 +3044,9 @@ static int rt5682_resume(struct snd_soc_component *component)
+                       RT5682_PWR_CBJ, RT5682_PWR_CBJ);
+       }
++      rt5682->jack_type = 0;
+       mod_delayed_work(system_power_efficient_wq,
+-              &rt5682->jack_detect_work, msecs_to_jiffies(250));
++              &rt5682->jack_detect_work, msecs_to_jiffies(0));
+       return 0;
+ }
+diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
+index 8e3244a62c16..f866d207d1bd 100644
+--- a/sound/soc/codecs/rt5682.h
++++ b/sound/soc/codecs/rt5682.h
+@@ -1462,6 +1462,7 @@ struct rt5682_priv {
+       int jack_type;
+       int irq_work_delay_time;
++      struct mutex jdet_mutex;
+ };
+ extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
+-- 
+2.35.1
+
diff --git a/queue-5.15/ath11k-add-hw_param-for-wakeup_mhi.patch b/queue-5.15/ath11k-add-hw_param-for-wakeup_mhi.patch
new file mode 100644 (file)
index 0000000..9d2700a
--- /dev/null
@@ -0,0 +1,151 @@
+From e21ac40cdf6c0767cda95ef71764207abbbbadaa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Nov 2021 09:39:41 +0200
+Subject: ath11k: add hw_param for wakeup_mhi
+
+From: Seevalamuthu Mariappan <quic_seevalam@quicinc.com>
+
+[ Upstream commit 081e2d6476e30399433b509684d5da4d1844e430 ]
+
+Wakeup mhi is needed before pci_read/write only for QCA6390 and WCN6855. Since
+wakeup & release mhi is enabled for all hardwares, below mhi assert is seen in
+QCN9074 when doing 'rmmod ath11k_pci':
+
+       Kernel panic - not syncing: dev_wake != 0
+       CPU: 2 PID: 13535 Comm: procd Not tainted 4.4.60 #1
+       Hardware name: Generic DT based system
+       [<80316dac>] (unwind_backtrace) from [<80313700>] (show_stack+0x10/0x14)
+       [<80313700>] (show_stack) from [<805135dc>] (dump_stack+0x7c/0x9c)
+       [<805135dc>] (dump_stack) from [<8032136c>] (panic+0x84/0x1f8)
+       [<8032136c>] (panic) from [<80549b24>] (mhi_pm_disable_transition+0x3b8/0x5b8)
+       [<80549b24>] (mhi_pm_disable_transition) from [<80549ddc>] (mhi_power_down+0xb8/0x100)
+       [<80549ddc>] (mhi_power_down) from [<7f5242b0>] (ath11k_mhi_op_status_cb+0x284/0x3ac [ath11k_pci])
+       [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process
+       [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process
+       [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process
+       [<7f5242b0>] (ath11k_mhi_op_status_cb [ath11k_pci]) from [<7f524878>] (ath11k_mhi_stop+0x10/0x20 [ath11k_pci])
+       [<7f524878>] (ath11k_mhi_stop [ath11k_pci]) from [<7f525b94>] (ath11k_pci_power_down+0x54/0x90 [ath11k_pci])
+       [<7f525b94>] (ath11k_pci_power_down [ath11k_pci]) from [<8056b2a8>] (pci_device_shutdown+0x30/0x44)
+       [<8056b2a8>] (pci_device_shutdown) from [<805cfa0c>] (device_shutdown+0x124/0x174)
+       [<805cfa0c>] (device_shutdown) from [<8033aaa4>] (kernel_restart+0xc/0x50)
+       [<8033aaa4>] (kernel_restart) from [<8033ada8>] (SyS_reboot+0x178/0x1ec)
+       [<8033ada8>] (SyS_reboot) from [<80301b80>] (ret_fast_syscall+0x0/0x34)
+
+Hence, disable wakeup/release mhi using hw_param for other hardwares.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01060-QCAHKSWPL_SILICONZ-1
+
+Fixes: a05bd8513335 ("ath11k: read and write registers below unwindowed address")
+Signed-off-by: Seevalamuthu Mariappan <quic_seevalam@quicinc.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/1636702019-26142-1-git-send-email-quic_seevalam@quicinc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/core.c |  5 +++++
+ drivers/net/wireless/ath/ath11k/hw.h   |  1 +
+ drivers/net/wireless/ath/ath11k/pci.c  | 12 ++++++++----
+ 3 files changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
+index 7dcf6b13f794..48b4151e13a3 100644
+--- a/drivers/net/wireless/ath/ath11k/core.c
++++ b/drivers/net/wireless/ath/ath11k/core.c
+@@ -71,6 +71,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+               .supports_suspend = false,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+               .fix_l1ss = true,
++              .wakeup_mhi = false,
+       },
+       {
+               .hw_rev = ATH11K_HW_IPQ6018_HW10,
+@@ -112,6 +113,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+               .supports_suspend = false,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+               .fix_l1ss = true,
++              .wakeup_mhi = false,
+       },
+       {
+               .name = "qca6390 hw2.0",
+@@ -152,6 +154,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+               .supports_suspend = true,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+               .fix_l1ss = true,
++              .wakeup_mhi = true,
+       },
+       {
+               .name = "qcn9074 hw1.0",
+@@ -190,6 +193,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+               .supports_suspend = false,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
+               .fix_l1ss = true,
++              .wakeup_mhi = false,
+       },
+       {
+               .name = "wcn6855 hw2.0",
+@@ -230,6 +234,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+               .supports_suspend = true,
+               .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
+               .fix_l1ss = false,
++              .wakeup_mhi = true,
+       },
+ };
+diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
+index 62f5978b3005..4fe051625edf 100644
+--- a/drivers/net/wireless/ath/ath11k/hw.h
++++ b/drivers/net/wireless/ath/ath11k/hw.h
+@@ -163,6 +163,7 @@ struct ath11k_hw_params {
+       bool supports_suspend;
+       u32 hal_desc_sz;
+       bool fix_l1ss;
++      bool wakeup_mhi;
+ };
+ struct ath11k_hw_ops {
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 353a2d669fcd..7d0be9388f89 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -182,7 +182,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
+       /* for offset beyond BAR + 4K - 32, may
+        * need to wakeup MHI to access.
+        */
+-      if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++      if (ab->hw_params.wakeup_mhi &&
++          test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+           offset >= ACCESS_ALWAYS_OFF)
+               mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
+@@ -206,7 +207,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
+               }
+       }
+-      if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++      if (ab->hw_params.wakeup_mhi &&
++          test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+           offset >= ACCESS_ALWAYS_OFF)
+               mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
+ }
+@@ -219,7 +221,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
+       /* for offset beyond BAR + 4K - 32, may
+        * need to wakeup MHI to access.
+        */
+-      if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++      if (ab->hw_params.wakeup_mhi &&
++          test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+           offset >= ACCESS_ALWAYS_OFF)
+               mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
+@@ -243,7 +246,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
+               }
+       }
+-      if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++      if (ab->hw_params.wakeup_mhi &&
++          test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+           offset >= ACCESS_ALWAYS_OFF)
+               mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
+-- 
+2.35.1
+
diff --git a/queue-5.15/batman-adv-use-netif_rx.patch b/queue-5.15/batman-adv-use-netif_rx.patch
new file mode 100644 (file)
index 0000000..3ec4fc3
--- /dev/null
@@ -0,0 +1,46 @@
+From 97de25fc18f995bfb8d2773b427728faafa26c89 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 6 Mar 2022 22:57:48 +0100
+Subject: batman-adv: Use netif_rx().
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+[ Upstream commit 94da81e2fc4285db373fe9a1eb012c2ee205b110 ]
+
+Since commit
+   baebdf48c3600 ("net: dev: Makes sure netif_rx() can be invoked in any context.")
+
+the function netif_rx() can be used in preemptible/thread context as
+well as in interrupt context.
+
+Use netif_rx().
+
+Cc: Antonio Quartulli <a@unstable.cc>
+Cc: Marek Lindner <mareklindner@neomailbox.ch>
+Cc: Simon Wunderlich <sw@simonwunderlich.de>
+Cc: Sven Eckelmann <sven@narfation.org>
+Cc: b.a.t.m.a.n@lists.open-mesh.org
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Acked-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/batman-adv/bridge_loop_avoidance.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
+index 17687848daec..11f6ef657d82 100644
+--- a/net/batman-adv/bridge_loop_avoidance.c
++++ b/net/batman-adv/bridge_loop_avoidance.c
+@@ -443,7 +443,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
+       batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
+                          skb->len + ETH_HLEN);
+-      netif_rx_any_context(skb);
++      netif_rx(skb);
+ out:
+       batadv_hardif_put(primary_if);
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch b/queue-5.15/block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch
new file mode 100644 (file)
index 0000000..92a1e9c
--- /dev/null
@@ -0,0 +1,181 @@
+From 1bbb367d99228ae0e7f9a6c3dab1a2718d58eab1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 13 Mar 2022 21:15:02 -1000
+Subject: block: fix rq-qos breakage from skipping rq_qos_done_bio()
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit aa1b46dcdc7baaf5fec0be25782ef24b26aa209e ]
+
+a647a524a467 ("block: don't call rq_qos_ops->done_bio if the bio isn't
+tracked") made bio_endio() skip rq_qos_done_bio() if BIO_TRACKED is not set.
+While this fixed a potential oops, it also broke blk-iocost by skipping the
+done_bio callback for merged bios.
+
+Before, whether a bio goes through rq_qos_throttle() or rq_qos_merge(),
+rq_qos_done_bio() would be called on the bio on completion with BIO_TRACKED
+distinguishing the former from the latter. rq_qos_done_bio() is not called
+for bios which wenth through rq_qos_merge(). This royally confuses
+blk-iocost as the merged bios never finish and are considered perpetually
+in-flight.
+
+One reliably reproducible failure mode is an intermediate cgroup geting
+stuck active preventing its children from being activated due to the
+leaf-only rule, leading to loss of control. The following is from
+resctl-bench protection scenario which emulates isolating a web server like
+workload from a memory bomb run on an iocost configuration which should
+yield a reasonable level of protection.
+
+  # cat /sys/block/nvme2n1/device/model
+  Samsung SSD 970 PRO 512GB
+  # cat /sys/fs/cgroup/io.cost.model
+  259:0 ctrl=user model=linear rbps=834913556 rseqiops=93622 rrandiops=102913 wbps=618985353 wseqiops=72325 wrandiops=71025
+  # cat /sys/fs/cgroup/io.cost.qos
+  259:0 enable=1 ctrl=user rpct=95.00 rlat=18776 wpct=95.00 wlat=8897 min=60.00 max=100.00
+  # resctl-bench -m 29.6G -r out.json run protection::scenario=mem-hog,loops=1
+  ...
+  Memory Hog Summary
+  ==================
+
+  IO Latency: R p50=242u:336u/2.5m p90=794u:1.4m/7.5m p99=2.7m:8.0m/62.5m max=8.0m:36.4m/350m
+              W p50=221u:323u/1.5m p90=709u:1.2m/5.5m p99=1.5m:2.5m/9.5m max=6.9m:35.9m/350m
+
+  Isolation and Request Latency Impact Distributions:
+
+                min   p01   p05   p10   p25   p50   p75   p90   p95   p99   max  mean stdev
+  isol%       15.90 15.90 15.90 40.05 57.24 59.07 60.01 74.63 74.63 90.35 90.35 58.12 15.82
+  lat-imp%        0     0     0     0     0  4.55 14.68 15.54 233.5 548.1 548.1 53.88 143.6
+
+  Result: isol=58.12:15.82% lat_imp=53.88%:143.6 work_csv=100.0% missing=3.96%
+
+The isolation result of 58.12% is close to what this device would show
+without any IO control.
+
+Fix it by introducing a new flag BIO_QOS_MERGED to mark merged bios and
+calling rq_qos_done_bio() on them too. For consistency and clarity, rename
+BIO_TRACKED to BIO_QOS_THROTTLED. The flag checks are moved into
+rq_qos_done_bio() so that it's next to the code paths that set the flags.
+
+With the patch applied, the above same benchmark shows:
+
+  # resctl-bench -m 29.6G -r out.json run protection::scenario=mem-hog,loops=1
+  ...
+  Memory Hog Summary
+  ==================
+
+  IO Latency: R p50=123u:84.4u/985u p90=322u:256u/2.5m p99=1.6m:1.4m/9.5m max=11.1m:36.0m/350m
+              W p50=429u:274u/995u p90=1.7m:1.3m/4.5m p99=3.4m:2.7m/11.5m max=7.9m:5.9m/26.5m
+
+  Isolation and Request Latency Impact Distributions:
+
+                min   p01   p05   p10   p25   p50   p75   p90   p95   p99   max  mean stdev
+  isol%       84.91 84.91 89.51 90.73 92.31 94.49 96.36 98.04 98.71 100.0 100.0 94.42  2.81
+  lat-imp%        0     0     0     0     0  2.81  5.73 11.11 13.92 17.53 22.61  4.10  4.68
+
+  Result: isol=94.42:2.81% lat_imp=4.10%:4.68 work_csv=58.34% missing=0%
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Fixes: a647a524a467 ("block: don't call rq_qos_ops->done_bio if the bio isn't tracked")
+Cc: stable@vger.kernel.org # v5.15+
+Cc: Ming Lei <ming.lei@redhat.com>
+Cc: Yu Kuai <yukuai3@huawei.com>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Link: https://lore.kernel.org/r/Yi7rdrzQEHjJLGKB@slm.duckdns.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/bio.c               |  3 +--
+ block/blk-iolatency.c     |  2 +-
+ block/blk-rq-qos.h        | 20 +++++++++++---------
+ include/linux/blk_types.h |  3 ++-
+ 4 files changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/block/bio.c b/block/bio.c
+index 365bb6362669..b8a8bfba714f 100644
+--- a/block/bio.c
++++ b/block/bio.c
+@@ -1470,8 +1470,7 @@ void bio_endio(struct bio *bio)
+       if (!bio_integrity_endio(bio))
+               return;
+-      if (bio->bi_bdev && bio_flagged(bio, BIO_TRACKED))
+-              rq_qos_done_bio(bdev_get_queue(bio->bi_bdev), bio);
++      rq_qos_done_bio(bio);
+       if (bio->bi_bdev && bio_flagged(bio, BIO_TRACE_COMPLETION)) {
+               trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio);
+diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
+index ce3847499d85..d85f30a85ee7 100644
+--- a/block/blk-iolatency.c
++++ b/block/blk-iolatency.c
+@@ -601,7 +601,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
+       int inflight = 0;
+       blkg = bio->bi_blkg;
+-      if (!blkg || !bio_flagged(bio, BIO_TRACKED))
++      if (!blkg || !bio_flagged(bio, BIO_QOS_THROTTLED))
+               return;
+       iolat = blkg_to_lat(bio->bi_blkg);
+diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h
+index 3cfbc8668cba..68267007da1c 100644
+--- a/block/blk-rq-qos.h
++++ b/block/blk-rq-qos.h
+@@ -177,20 +177,20 @@ static inline void rq_qos_requeue(struct request_queue *q, struct request *rq)
+               __rq_qos_requeue(q->rq_qos, rq);
+ }
+-static inline void rq_qos_done_bio(struct request_queue *q, struct bio *bio)
++static inline void rq_qos_done_bio(struct bio *bio)
+ {
+-      if (q->rq_qos)
+-              __rq_qos_done_bio(q->rq_qos, bio);
++      if (bio->bi_bdev && (bio_flagged(bio, BIO_QOS_THROTTLED) ||
++                           bio_flagged(bio, BIO_QOS_MERGED))) {
++              struct request_queue *q = bdev_get_queue(bio->bi_bdev);
++              if (q->rq_qos)
++                      __rq_qos_done_bio(q->rq_qos, bio);
++      }
+ }
+ static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio)
+ {
+-      /*
+-       * BIO_TRACKED lets controllers know that a bio went through the
+-       * normal rq_qos path.
+-       */
+       if (q->rq_qos) {
+-              bio_set_flag(bio, BIO_TRACKED);
++              bio_set_flag(bio, BIO_QOS_THROTTLED);
+               __rq_qos_throttle(q->rq_qos, bio);
+       }
+ }
+@@ -205,8 +205,10 @@ static inline void rq_qos_track(struct request_queue *q, struct request *rq,
+ static inline void rq_qos_merge(struct request_queue *q, struct request *rq,
+                               struct bio *bio)
+ {
+-      if (q->rq_qos)
++      if (q->rq_qos) {
++              bio_set_flag(bio, BIO_QOS_MERGED);
+               __rq_qos_merge(q->rq_qos, rq, bio);
++      }
+ }
+ static inline void rq_qos_queue_depth_changed(struct request_queue *q)
+diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
+index 17c92c0f15b2..36ce3d0fb9f3 100644
+--- a/include/linux/blk_types.h
++++ b/include/linux/blk_types.h
+@@ -294,7 +294,8 @@ enum {
+       BIO_TRACE_COMPLETION,   /* bio_endio() should trace the final completion
+                                * of this bio. */
+       BIO_CGROUP_ACCT,        /* has been accounted to a cgroup */
+-      BIO_TRACKED,            /* set if bio goes through the rq_qos path */
++      BIO_QOS_THROTTLED,      /* bio went through rq_qos throttle path */
++      BIO_QOS_MERGED,         /* but went through rq_qos merge path */
+       BIO_REMAPPED,
+       BIO_ZONE_WRITE_LOCKED,  /* Owns a zoned device zone write lock */
+       BIO_PERCPU_CACHE,       /* can participate in per-cpu alloc cache */
+-- 
+2.35.1
+
diff --git a/queue-5.15/block-only-mark-bio-as-tracked-if-it-really-is-track.patch b/queue-5.15/block-only-mark-bio-as-tracked-if-it-really-is-track.patch
new file mode 100644 (file)
index 0000000..a83a4d5
--- /dev/null
@@ -0,0 +1,44 @@
+From 6a52efe5286829a926e77cfcfa00024fadfe5d1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Oct 2021 20:06:18 -0600
+Subject: block: only mark bio as tracked if it really is tracked
+
+From: Jens Axboe <axboe@kernel.dk>
+
+[ Upstream commit 90b8faa0e8de1b02b619fb33f6c6e1e13e7d1d70 ]
+
+We set BIO_TRACKED unconditionally when rq_qos_throttle() is called, even
+though we may not even have an rq_qos handler. Only mark it as TRACKED if
+it really is potentially tracked.
+
+This saves considerable time for the case where the bio isn't tracked:
+
+     2.64%     -1.65%  [kernel.vmlinux]  [k] bio_endio
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-rq-qos.h | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h
+index f000f83e0621..3cfbc8668cba 100644
+--- a/block/blk-rq-qos.h
++++ b/block/blk-rq-qos.h
+@@ -189,9 +189,10 @@ static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio)
+        * BIO_TRACKED lets controllers know that a bio went through the
+        * normal rq_qos path.
+        */
+-      bio_set_flag(bio, BIO_TRACKED);
+-      if (q->rq_qos)
++      if (q->rq_qos) {
++              bio_set_flag(bio, BIO_TRACKED);
+               __rq_qos_throttle(q->rq_qos, bio);
++      }
+ }
+ static inline void rq_qos_track(struct request_queue *q, struct request *rq,
+-- 
+2.35.1
+
diff --git a/queue-5.15/block-use-bdev_get_queue-in-bio.c.patch b/queue-5.15/block-use-bdev_get_queue-in-bio.c.patch
new file mode 100644 (file)
index 0000000..8d4811c
--- /dev/null
@@ -0,0 +1,67 @@
+From 05769e3e67cc0426abc8f239b413a0bec3778364 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Oct 2021 15:03:28 +0100
+Subject: block: use bdev_get_queue() in bio.c
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 3caee4634be68e755d2fb130962f1623661dbd5b ]
+
+Convert bdev->bd_disk->queue to bdev_get_queue(), it's uses a cached
+queue pointer and so is faster.
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/85c36ea784d285a5075baa10049e6b59e15fb484.1634219547.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/bio.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/block/bio.c b/block/bio.c
+index 8381c6690dd6..365bb6362669 100644
+--- a/block/bio.c
++++ b/block/bio.c
+@@ -910,7 +910,7 @@ EXPORT_SYMBOL(bio_add_pc_page);
+ int bio_add_zone_append_page(struct bio *bio, struct page *page,
+                            unsigned int len, unsigned int offset)
+ {
+-      struct request_queue *q = bio->bi_bdev->bd_disk->queue;
++      struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+       bool same_page = false;
+       if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_ZONE_APPEND))
+@@ -1054,7 +1054,7 @@ static int bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter)
+ static int bio_iov_bvec_set_append(struct bio *bio, struct iov_iter *iter)
+ {
+-      struct request_queue *q = bio->bi_bdev->bd_disk->queue;
++      struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+       struct iov_iter i = *iter;
+       iov_iter_truncate(&i, queue_max_zone_append_sectors(q) << 9);
+@@ -1132,7 +1132,7 @@ static int __bio_iov_append_get_pages(struct bio *bio, struct iov_iter *iter)
+ {
+       unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
+       unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
+-      struct request_queue *q = bio->bi_bdev->bd_disk->queue;
++      struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+       unsigned int max_append_sectors = queue_max_zone_append_sectors(q);
+       struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
+       struct page **pages = (struct page **)bv;
+@@ -1471,10 +1471,10 @@ void bio_endio(struct bio *bio)
+               return;
+       if (bio->bi_bdev && bio_flagged(bio, BIO_TRACKED))
+-              rq_qos_done_bio(bio->bi_bdev->bd_disk->queue, bio);
++              rq_qos_done_bio(bdev_get_queue(bio->bi_bdev), bio);
+       if (bio->bi_bdev && bio_flagged(bio, BIO_TRACE_COMPLETION)) {
+-              trace_block_bio_complete(bio->bi_bdev->bd_disk->queue, bio);
++              trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio);
+               bio_clear_flag(bio, BIO_TRACE_COMPLETION);
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.15/bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch b/queue-5.15/bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch
new file mode 100644 (file)
index 0000000..f5504cd
--- /dev/null
@@ -0,0 +1,86 @@
+From de517be1dd5d98cecb549658b856c0d4c1f5e35b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 May 2022 06:22:15 +0800
+Subject: Bluetooth: btmtksdio: fix use-after-free at btmtksdio_recv_event
+
+From: Sean Wang <sean.wang@mediatek.com>
+
+[ Upstream commit 0fab6361c4ba17d1b43a991bef4238a3c1754d35 ]
+
+We should not access skb buffer data anymore after hci_recv_frame was
+called.
+
+[   39.634809] BUG: KASAN: use-after-free in btmtksdio_recv_event+0x1b0
+[   39.634855] Read of size 1 at addr ffffff80cf28a60d by task kworker
+[   39.634962] Call trace:
+[   39.634974]  dump_backtrace+0x0/0x3b8
+[   39.634999]  show_stack+0x20/0x2c
+[   39.635016]  dump_stack_lvl+0x60/0x78
+[   39.635040]  print_address_description+0x70/0x2f0
+[   39.635062]  kasan_report+0x154/0x194
+[   39.635079]  __asan_report_load1_noabort+0x44/0x50
+[   39.635099]  btmtksdio_recv_event+0x1b0/0x1c4
+[   39.635129]  btmtksdio_txrx_work+0x6cc/0xac4
+[   39.635157]  process_one_work+0x560/0xc5c
+[   39.635177]  worker_thread+0x7ec/0xcc0
+[   39.635195]  kthread+0x2d0/0x3d0
+[   39.635215]  ret_from_fork+0x10/0x20
+[   39.635247] Allocated by task 0:
+[   39.635260] (stack is not available)
+[   39.635281] Freed by task 2392:
+[   39.635295]  kasan_save_stack+0x38/0x68
+[   39.635319]  kasan_set_track+0x28/0x3c
+[   39.635338]  kasan_set_free_info+0x28/0x4c
+[   39.635357]  ____kasan_slab_free+0x104/0x150
+[   39.635374]  __kasan_slab_free+0x18/0x28
+[   39.635391]  slab_free_freelist_hook+0x114/0x248
+[   39.635410]  kfree+0xf8/0x2b4
+[   39.635427]  skb_free_head+0x58/0x98
+[   39.635447]  skb_release_data+0x2f4/0x410
+[   39.635464]  skb_release_all+0x50/0x60
+[   39.635481]  kfree_skb+0xc8/0x25c
+[   39.635498]  hci_event_packet+0x894/0xca4 [bluetooth]
+[   39.635721]  hci_rx_work+0x1c8/0x68c [bluetooth]
+[   39.635925]  process_one_work+0x560/0xc5c
+[   39.635951]  worker_thread+0x7ec/0xcc0
+[   39.635970]  kthread+0x2d0/0x3d0
+[   39.635990]  ret_from_fork+0x10/0x20
+[   39.636021] The buggy address belongs to the object at ffffff80cf28a600
+                which belongs to the cache kmalloc-512 of size 512
+[   39.636039] The buggy address is located 13 bytes inside of
+                512-byte region [ffffff80cf28a600, ffffff80cf28a800)
+
+Fixes: 9aebfd4a2200 ("Bluetooth: mediatek: add support for MediaTek MT7663S and MT7668S SDIO devices")
+Co-developed-by: Yake Yang <yake.yang@mediatek.com>
+Signed-off-by: Yake Yang <yake.yang@mediatek.com>
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btmtksdio.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
+index ff1f5dfbb6db..d66e4df171d2 100644
+--- a/drivers/bluetooth/btmtksdio.c
++++ b/drivers/bluetooth/btmtksdio.c
+@@ -331,6 +331,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+       struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+       struct hci_event_hdr *hdr = (void *)skb->data;
++      u8 evt = hdr->evt;
+       int err;
+       /* Fix up the vendor event id with 0xff for vendor specific instead
+@@ -355,7 +356,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+       if (err < 0)
+               goto err_free_skb;
+-      if (hdr->evt == HCI_EV_VENDOR) {
++      if (evt == HCI_EV_VENDOR) {
+               if (test_and_clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT,
+                                      &bdev->tx_state)) {
+                       /* Barrier to sync with other CPUs */
+-- 
+2.35.1
+
diff --git a/queue-5.15/bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch b/queue-5.15/bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch
new file mode 100644 (file)
index 0000000..c35ba57
--- /dev/null
@@ -0,0 +1,96 @@
+From de9ef8d7910fd92362858caeb10aab16c2b8426a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 23 Apr 2022 00:31:17 +0200
+Subject: Bluetooth: protect le accept and resolv lists with hdev->lock
+
+From: Niels Dossche <dossche.niels@gmail.com>
+
+[ Upstream commit 5e2b6064cbc5fd582396768c5f9583f65085e368 ]
+
+Concurrent operations from events on le_{accept,resolv}_list are
+currently unprotected by hdev->lock.
+Most existing code do already protect the lists with that lock.
+This can be observed in hci_debugfs and hci_sync.
+Add the protection for these events too.
+
+Fixes: b950aa88638c ("Bluetooth: Add definitions and track LE resolve list modification")
+Fixes: 0f36b589e4ee ("Bluetooth: Track LE white list modification via HCI commands")
+Signed-off-by: Niels Dossche <dossche.niels@gmail.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/hci_event.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 5ac3aca6deeb..2337e9275863 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -1559,7 +1559,9 @@ static void hci_cc_le_clear_accept_list(struct hci_dev *hdev,
+       if (status)
+               return;
++      hci_dev_lock(hdev);
+       hci_bdaddr_list_clear(&hdev->le_accept_list);
++      hci_dev_unlock(hdev);
+ }
+ static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev,
+@@ -1577,8 +1579,10 @@ static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev,
+       if (!sent)
+               return;
++      hci_dev_lock(hdev);
+       hci_bdaddr_list_add(&hdev->le_accept_list, &sent->bdaddr,
+                           sent->bdaddr_type);
++      hci_dev_unlock(hdev);
+ }
+ static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev,
+@@ -1596,8 +1600,10 @@ static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev,
+       if (!sent)
+               return;
++      hci_dev_lock(hdev);
+       hci_bdaddr_list_del(&hdev->le_accept_list, &sent->bdaddr,
+                           sent->bdaddr_type);
++      hci_dev_unlock(hdev);
+ }
+ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
+@@ -1661,9 +1667,11 @@ static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
+       if (!sent)
+               return;
++      hci_dev_lock(hdev);
+       hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
+                               sent->bdaddr_type, sent->peer_irk,
+                               sent->local_irk);
++      hci_dev_unlock(hdev);
+ }
+ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
+@@ -1681,8 +1689,10 @@ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
+       if (!sent)
+               return;
++      hci_dev_lock(hdev);
+       hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
+                           sent->bdaddr_type);
++      hci_dev_unlock(hdev);
+ }
+ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
+@@ -1695,7 +1705,9 @@ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
+       if (status)
+               return;
++      hci_dev_lock(hdev);
+       hci_bdaddr_list_clear(&hdev->le_resolv_list);
++      hci_dev_unlock(hdev);
+ }
+ static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
+-- 
+2.35.1
+
diff --git a/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch b/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch
new file mode 100644 (file)
index 0000000..2a4899b
--- /dev/null
@@ -0,0 +1,59 @@
+From 4f904a19f459c59d7ad52227a79580cd18b5552d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Dec 2021 23:10:18 +0800
+Subject: bpf, arm64: Use emit_addr_mov_i64() for BPF_PSEUDO_FUNC
+
+From: Hou Tao <houtao1@huawei.com>
+
+[ Upstream commit e4a41c2c1fa916547e63440c73a51a5eb06247af ]
+
+The following error is reported when running "./test_progs -t for_each"
+under arm64:
+
+  bpf_jit: multi-func JIT bug 58 != 56
+  [...]
+  JIT doesn't support bpf-to-bpf calls
+
+The root cause is the size of BPF_PSEUDO_FUNC instruction increases
+from 2 to 3 after the address of called bpf-function is settled and
+there are two bpf-to-bpf calls in test_pkt_access. The generated
+instructions are shown below:
+
+  0x48:  21 00 C0 D2    movz x1, #0x1, lsl #32
+  0x4c:  21 00 80 F2    movk x1, #0x1
+
+  0x48:  E1 3F C0 92    movn x1, #0x1ff, lsl #32
+  0x4c:  41 FE A2 F2    movk x1, #0x17f2, lsl #16
+  0x50:  81 70 9F F2    movk x1, #0xfb84
+
+Fixing it by using emit_addr_mov_i64() for BPF_PSEUDO_FUNC, so
+the size of jited image will not change.
+
+Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
+Signed-off-by: Hou Tao <houtao1@huawei.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/bpf/20211231151018.3781550-1-houtao1@huawei.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/net/bpf_jit_comp.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
+index 95439bbe5df8..4895b4d7e150 100644
+--- a/arch/arm64/net/bpf_jit_comp.c
++++ b/arch/arm64/net/bpf_jit_comp.c
+@@ -788,7 +788,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
+               u64 imm64;
+               imm64 = (u64)insn1.imm << 32 | (u32)imm;
+-              emit_a64_mov_i64(dst, imm64, ctx);
++              if (bpf_pseudo_func(insn))
++                      emit_addr_mov_i64(dst, imm64, ctx);
++              else
++                      emit_a64_mov_i64(dst, imm64, ctx);
+               return 1;
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch b/queue-5.15/btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch
new file mode 100644 (file)
index 0000000..70b5e29
--- /dev/null
@@ -0,0 +1,178 @@
+From d8d0e5d7162bc4215084e81b959efdd23219396f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Oct 2021 16:12:43 -0400
+Subject: btrfs: add a btrfs_get_dev_args_from_path helper
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+[ Upstream commit faa775c41d655a4786e9d53cb075a77bb5a75f66 ]
+
+We are going to want to populate our device lookup args outside of any
+locks and then do the actual device lookup later, so add a helper to do
+this work and make btrfs_find_device_by_devspec() use this helper for
+now.
+
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: Anand Jain <anand.jain@oracle.com>
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/volumes.c | 96 ++++++++++++++++++++++++++++++----------------
+ fs/btrfs/volumes.h |  4 ++
+ 2 files changed, 68 insertions(+), 32 deletions(-)
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 53417a1c5402..8d09e6d442b2 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -2361,45 +2361,81 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
+       btrfs_free_device(tgtdev);
+ }
+-static struct btrfs_device *btrfs_find_device_by_path(
+-              struct btrfs_fs_info *fs_info, const char *device_path)
++/**
++ * Populate args from device at path
++ *
++ * @fs_info:  the filesystem
++ * @args:     the args to populate
++ * @path:     the path to the device
++ *
++ * This will read the super block of the device at @path and populate @args with
++ * the devid, fsid, and uuid.  This is meant to be used for ioctls that need to
++ * lookup a device to operate on, but need to do it before we take any locks.
++ * This properly handles the special case of "missing" that a user may pass in,
++ * and does some basic sanity checks.  The caller must make sure that @path is
++ * properly NUL terminated before calling in, and must call
++ * btrfs_put_dev_args_from_path() in order to free up the temporary fsid and
++ * uuid buffers.
++ *
++ * Return: 0 for success, -errno for failure
++ */
++int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
++                               struct btrfs_dev_lookup_args *args,
++                               const char *path)
+ {
+-      BTRFS_DEV_LOOKUP_ARGS(args);
+-      int ret = 0;
+       struct btrfs_super_block *disk_super;
+       struct block_device *bdev;
+-      struct btrfs_device *device;
++      int ret;
+-      ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ,
+-                                  fs_info->bdev_holder, 0, &bdev, &disk_super);
+-      if (ret)
+-              return ERR_PTR(ret);
++      if (!path || !path[0])
++              return -EINVAL;
++      if (!strcmp(path, "missing")) {
++              args->missing = true;
++              return 0;
++      }
++
++      args->uuid = kzalloc(BTRFS_UUID_SIZE, GFP_KERNEL);
++      args->fsid = kzalloc(BTRFS_FSID_SIZE, GFP_KERNEL);
++      if (!args->uuid || !args->fsid) {
++              btrfs_put_dev_args_from_path(args);
++              return -ENOMEM;
++      }
+-      args.devid = btrfs_stack_device_id(&disk_super->dev_item);
+-      args.uuid = disk_super->dev_item.uuid;
++      ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0,
++                                  &bdev, &disk_super);
++      if (ret)
++              return ret;
++      args->devid = btrfs_stack_device_id(&disk_super->dev_item);
++      memcpy(args->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE);
+       if (btrfs_fs_incompat(fs_info, METADATA_UUID))
+-              args.fsid = disk_super->metadata_uuid;
++              memcpy(args->fsid, disk_super->metadata_uuid, BTRFS_FSID_SIZE);
+       else
+-              args.fsid = disk_super->fsid;
+-
+-      device = btrfs_find_device(fs_info->fs_devices, &args);
+-
++              memcpy(args->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
+       btrfs_release_disk_super(disk_super);
+-      if (!device)
+-              device = ERR_PTR(-ENOENT);
+       blkdev_put(bdev, FMODE_READ);
+-      return device;
++      return 0;
+ }
+ /*
+- * Lookup a device given by device id, or the path if the id is 0.
++ * Only use this jointly with btrfs_get_dev_args_from_path() because we will
++ * allocate our ->uuid and ->fsid pointers, everybody else uses local variables
++ * that don't need to be freed.
+  */
++void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args)
++{
++      kfree(args->uuid);
++      kfree(args->fsid);
++      args->uuid = NULL;
++      args->fsid = NULL;
++}
++
+ struct btrfs_device *btrfs_find_device_by_devspec(
+               struct btrfs_fs_info *fs_info, u64 devid,
+               const char *device_path)
+ {
+       BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_device *device;
++      int ret;
+       if (devid) {
+               args.devid = devid;
+@@ -2409,18 +2445,14 @@ struct btrfs_device *btrfs_find_device_by_devspec(
+               return device;
+       }
+-      if (!device_path || !device_path[0])
+-              return ERR_PTR(-EINVAL);
+-
+-      if (strcmp(device_path, "missing") == 0) {
+-              args.missing = true;
+-              device = btrfs_find_device(fs_info->fs_devices, &args);
+-              if (!device)
+-                      return ERR_PTR(-ENOENT);
+-              return device;
+-      }
+-
+-      return btrfs_find_device_by_path(fs_info, device_path);
++      ret = btrfs_get_dev_args_from_path(fs_info, &args, device_path);
++      if (ret)
++              return ERR_PTR(ret);
++      device = btrfs_find_device(fs_info->fs_devices, &args);
++      btrfs_put_dev_args_from_path(&args);
++      if (!device)
++              return ERR_PTR(-ENOENT);
++      return device;
+ }
+ /*
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index f3b1380f45ad..d1df03f77e29 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -487,9 +487,13 @@ void btrfs_assign_next_active_device(struct btrfs_device *device,
+ struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info,
+                                                 u64 devid,
+                                                 const char *devpath);
++int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
++                               struct btrfs_dev_lookup_args *args,
++                               const char *path);
+ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
+                                       const u64 *devid,
+                                       const u8 *uuid);
++void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
+ void btrfs_free_device(struct btrfs_device *device);
+ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+                   const char *device_path, u64 devid,
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch b/queue-5.15/btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch
new file mode 100644 (file)
index 0000000..2897a12
--- /dev/null
@@ -0,0 +1,271 @@
+From 6fc3ca40a97dc1507a2bc03abb0c8c84986793e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Oct 2021 11:21:35 +0300
+Subject: btrfs: add additional parameters to
+ btrfs_init_tree_ref/btrfs_init_data_ref
+
+From: Nikolay Borisov <nborisov@suse.com>
+
+[ Upstream commit f42c5da6c12e990d8ec415199600b4d593c63bf5 ]
+
+In order to make 'real_root' used only in ref-verify it's required to
+have the necessary context to perform the same checks that this member
+is used for. So add 'mod_root' which will contain the root on behalf of
+which a delayed ref was created and a 'skip_group' parameter which
+will contain callsite-specific override of skip_qgroup.
+
+Signed-off-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/delayed-ref.h |  5 +++--
+ fs/btrfs/extent-tree.c | 17 +++++++++++------
+ fs/btrfs/file.c        | 13 ++++++++-----
+ fs/btrfs/inode.c       |  3 ++-
+ fs/btrfs/relocation.c  | 21 ++++++++++++++-------
+ fs/btrfs/tree-log.c    |  2 +-
+ 6 files changed, 39 insertions(+), 22 deletions(-)
+
+diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
+index e22fba272e4f..31266ba1d430 100644
+--- a/fs/btrfs/delayed-ref.h
++++ b/fs/btrfs/delayed-ref.h
+@@ -271,7 +271,7 @@ static inline void btrfs_init_generic_ref(struct btrfs_ref *generic_ref,
+ }
+ static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref,
+-                              int level, u64 root)
++                              int level, u64 root, u64 mod_root, bool skip_qgroup)
+ {
+       /* If @real_root not set, use @root as fallback */
+       if (!generic_ref->real_root)
+@@ -282,7 +282,8 @@ static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref,
+ }
+ static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref,
+-                              u64 ref_root, u64 ino, u64 offset)
++                              u64 ref_root, u64 ino, u64 offset, u64 mod_root,
++                              bool skip_qgroup)
+ {
+       /* If @real_root not set, use @root as fallback */
+       if (!generic_ref->real_root)
+diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
+index 514adc83577f..e01b9344fb9c 100644
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2440,7 +2440,8 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
+                                              num_bytes, parent);
+                       generic_ref.real_root = root->root_key.objectid;
+                       btrfs_init_data_ref(&generic_ref, ref_root, key.objectid,
+-                                          key.offset);
++                                          key.offset, root->root_key.objectid,
++                                          for_reloc);
+                       generic_ref.skip_qgroup = for_reloc;
+                       if (inc)
+                               ret = btrfs_inc_extent_ref(trans, &generic_ref);
+@@ -2454,7 +2455,8 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
+                       btrfs_init_generic_ref(&generic_ref, action, bytenr,
+                                              num_bytes, parent);
+                       generic_ref.real_root = root->root_key.objectid;
+-                      btrfs_init_tree_ref(&generic_ref, level - 1, ref_root);
++                      btrfs_init_tree_ref(&generic_ref, level - 1, ref_root,
++                                          root->root_key.objectid, for_reloc);
+                       generic_ref.skip_qgroup = for_reloc;
+                       if (inc)
+                               ret = btrfs_inc_extent_ref(trans, &generic_ref);
+@@ -3289,7 +3291,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+       btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
+                              buf->start, buf->len, parent);
+       btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
+-                          root->root_key.objectid);
++                          root->root_key.objectid, 0, false);
+       if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
+               btrfs_ref_tree_mod(fs_info, &generic_ref);
+@@ -4705,7 +4707,8 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
+       btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT,
+                              ins->objectid, ins->offset, 0);
+-      btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, offset);
++      btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner,
++                          offset, 0, false);
+       btrfs_ref_tree_mod(root->fs_info, &generic_ref);
+       return btrfs_add_delayed_data_ref(trans, &generic_ref, ram_bytes);
+@@ -4898,7 +4901,8 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+               btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT,
+                                      ins.objectid, ins.offset, parent);
+               generic_ref.real_root = root->root_key.objectid;
+-              btrfs_init_tree_ref(&generic_ref, level, root_objectid);
++              btrfs_init_tree_ref(&generic_ref, level, root_objectid,
++                                  root->root_key.objectid, false);
+               btrfs_ref_tree_mod(fs_info, &generic_ref);
+               ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, extent_op);
+               if (ret)
+@@ -5315,7 +5319,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
+               btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
+                                      fs_info->nodesize, parent);
+-              btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid);
++              btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid,
++                                  0, false);
+               ret = btrfs_free_extent(trans, &ref);
+               if (ret)
+                       goto out_unlock;
+diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
+index a06c8366a8f4..1c597cd6c024 100644
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -869,7 +869,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
+                               btrfs_init_data_ref(&ref,
+                                               root->root_key.objectid,
+                                               new_key.objectid,
+-                                              args->start - extent_offset);
++                                              args->start - extent_offset,
++                                              0, false);
+                               ret = btrfs_inc_extent_ref(trans, &ref);
+                               BUG_ON(ret); /* -ENOMEM */
+                       }
+@@ -955,7 +956,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
+                               btrfs_init_data_ref(&ref,
+                                               root->root_key.objectid,
+                                               key.objectid,
+-                                              key.offset - extent_offset);
++                                              key.offset - extent_offset, 0,
++                                              false);
+                               ret = btrfs_free_extent(trans, &ref);
+                               BUG_ON(ret); /* -ENOMEM */
+                               args->bytes_found += extent_end - key.offset;
+@@ -1232,7 +1234,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
+               btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, bytenr,
+                                      num_bytes, 0);
+               btrfs_init_data_ref(&ref, root->root_key.objectid, ino,
+-                                  orig_offset);
++                                  orig_offset, 0, false);
+               ret = btrfs_inc_extent_ref(trans, &ref);
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
+@@ -1257,7 +1259,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
+       other_end = 0;
+       btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
+                              num_bytes, 0);
+-      btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset);
++      btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset,
++                          0, false);
+       if (extent_mergeable(leaf, path->slots[0] + 1,
+                            ino, bytenr, orig_offset,
+                            &other_start, &other_end)) {
+@@ -2715,7 +2718,7 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans,
+                                      extent_info->disk_len, 0);
+               ref_offset = extent_info->file_offset - extent_info->data_offset;
+               btrfs_init_data_ref(&ref, root->root_key.objectid,
+-                                  btrfs_ino(inode), ref_offset);
++                                  btrfs_ino(inode), ref_offset, 0, false);
+               ret = btrfs_inc_extent_ref(trans, &ref);
+       }
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 044d584c3467..d644dcaf3004 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4919,7 +4919,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
+                                       extent_start, extent_num_bytes, 0);
+                       ref.real_root = root->root_key.objectid;
+                       btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
+-                                      ino, extent_offset);
++                                      ino, extent_offset,
++                                      root->root_key.objectid, false);
+                       ret = btrfs_free_extent(trans, &ref);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, ret);
+diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
+index a6661f2ad2c0..0300770c0a89 100644
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -1147,7 +1147,8 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
+                                      num_bytes, parent);
+               ref.real_root = root->root_key.objectid;
+               btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
+-                                  key.objectid, key.offset);
++                                  key.objectid, key.offset,
++                                  root->root_key.objectid, false);
+               ret = btrfs_inc_extent_ref(trans, &ref);
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
+@@ -1158,7 +1159,8 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
+                                      num_bytes, parent);
+               ref.real_root = root->root_key.objectid;
+               btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
+-                                  key.objectid, key.offset);
++                                  key.objectid, key.offset,
++                                  root->root_key.objectid, false);
+               ret = btrfs_free_extent(trans, &ref);
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
+@@ -1368,7 +1370,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc,
+               btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, old_bytenr,
+                                      blocksize, path->nodes[level]->start);
+               ref.skip_qgroup = true;
+-              btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid);
++              btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid,
++                                  0, true);
+               ret = btrfs_inc_extent_ref(trans, &ref);
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
+@@ -1377,7 +1380,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc,
+               btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr,
+                                      blocksize, 0);
+               ref.skip_qgroup = true;
+-              btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid);
++              btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid, 0,
++                                  true);
+               ret = btrfs_inc_extent_ref(trans, &ref);
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
+@@ -1386,7 +1390,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc,
+               btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, new_bytenr,
+                                      blocksize, path->nodes[level]->start);
+-              btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid);
++              btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid,
++                                  0, true);
+               ref.skip_qgroup = true;
+               ret = btrfs_free_extent(trans, &ref);
+               if (ret) {
+@@ -1396,7 +1401,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc,
+               btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, old_bytenr,
+                                      blocksize, 0);
+-              btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid);
++              btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid,
++                                  0, true);
+               ref.skip_qgroup = true;
+               ret = btrfs_free_extent(trans, &ref);
+               if (ret) {
+@@ -2475,7 +2481,8 @@ static int do_relocation(struct btrfs_trans_handle *trans,
+                                              upper->eb->start);
+                       ref.real_root = root->root_key.objectid;
+                       btrfs_init_tree_ref(&ref, node->level,
+-                                          btrfs_header_owner(upper->eb));
++                                          btrfs_header_owner(upper->eb),
++                                          root->root_key.objectid, false);
+                       ret = btrfs_inc_extent_ref(trans, &ref);
+                       if (!ret)
+                               ret = btrfs_drop_subtree(trans, root, eb,
+diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
+index 1221d8483d63..bed6811476b0 100644
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -761,7 +761,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
+                                               ins.objectid, ins.offset, 0);
+                               btrfs_init_data_ref(&ref,
+                                               root->root_key.objectid,
+-                                              key->objectid, offset);
++                                              key->objectid, offset, 0, false);
+                               ret = btrfs_inc_extent_ref(trans, &ref);
+                               if (ret)
+                                       goto out;
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch b/queue-5.15/btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch
new file mode 100644 (file)
index 0000000..f1d87c2
--- /dev/null
@@ -0,0 +1,83 @@
+From a6683351a79b2437780e7b15aa466a8fb7722c55 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 3 Mar 2022 22:40:27 +0800
+Subject: btrfs: don't access possibly stale fs_info data in device_list_add
+
+From: Dongliang Mu <mudongliangabcd@gmail.com>
+
+[ Upstream commit 79c9234ba596e903907de20573fd4bcc85315b06 ]
+
+Syzbot reported a possible use-after-free in printing information
+in device_list_add.
+
+Very similar with the bug fixed by commit 0697d9a61099 ("btrfs: don't
+access possibly stale fs_info data for printing duplicate device"),
+but this time the use occurs in btrfs_info_in_rcu.
+
+  Call Trace:
+   kasan_report.cold+0x83/0xdf mm/kasan/report.c:459
+   btrfs_printk+0x395/0x425 fs/btrfs/super.c:244
+   device_list_add.cold+0xd7/0x2ed fs/btrfs/volumes.c:957
+   btrfs_scan_one_device+0x4c7/0x5c0 fs/btrfs/volumes.c:1387
+   btrfs_control_ioctl+0x12a/0x2d0 fs/btrfs/super.c:2409
+   vfs_ioctl fs/ioctl.c:51 [inline]
+   __do_sys_ioctl fs/ioctl.c:874 [inline]
+   __se_sys_ioctl fs/ioctl.c:860 [inline]
+   __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860
+   do_syscall_x64 arch/x86/entry/common.c:50 [inline]
+   do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
+   entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+Fix this by modifying device->fs_info to NULL too.
+
+Reported-and-tested-by: syzbot+82650a4e0ed38f218363@syzkaller.appspotmail.com
+CC: stable@vger.kernel.org # 4.19+
+Signed-off-by: Dongliang Mu <mudongliangabcd@gmail.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/volumes.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index cec54c6e1cdd..89ce0b449c22 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -955,6 +955,11 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+               /*
+                * We are going to replace the device path for a given devid,
+                * make sure it's the same device if the device is mounted
++               *
++               * NOTE: the device->fs_info may not be reliable here so pass
++               * in a NULL to message helpers instead. This avoids a possible
++               * use-after-free when the fs_info and fs_info->sb are already
++               * torn down.
+                */
+               if (device->bdev) {
+                       int error;
+@@ -968,12 +973,6 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+                       if (device->bdev->bd_dev != path_dev) {
+                               mutex_unlock(&fs_devices->device_list_mutex);
+-                              /*
+-                               * device->fs_info may not be reliable here, so
+-                               * pass in a NULL instead. This avoids a
+-                               * possible use-after-free when the fs_info and
+-                               * fs_info->sb are already torn down.
+-                               */
+                               btrfs_warn_in_rcu(NULL,
+       "duplicate device %s devid %llu generation %llu scanned by %s (%d)",
+                                                 path, devid, found_transid,
+@@ -981,7 +980,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+                                                 task_pid_nr(current));
+                               return ERR_PTR(-EEXIST);
+                       }
+-                      btrfs_info_in_rcu(device->fs_info,
++                      btrfs_info_in_rcu(NULL,
+       "devid %llu device path %s changed to %s scanned by %s (%d)",
+                                         devid, rcu_str_deref(device->name),
+                                         path, current->comm,
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch b/queue-5.15/btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch
new file mode 100644 (file)
index 0000000..1cf6b42
--- /dev/null
@@ -0,0 +1,457 @@
+From 88418df0ba0876e9bd115f9dd2ae6934d243a7a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Oct 2021 10:12:49 +0100
+Subject: btrfs: fix deadlock between chunk allocation and chunk btree
+ modifications
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 2bb2e00ed9787e52580bb651264b8d6a2b7a9dd2 ]
+
+When a task is doing some modification to the chunk btree and it is not in
+the context of a chunk allocation or a chunk removal, it can deadlock with
+another task that is currently allocating a new data or metadata chunk.
+
+These contexts are the following:
+
+* When relocating a system chunk, when we need to COW the extent buffers
+  that belong to the chunk btree;
+
+* When adding a new device (ioctl), where we need to add a new device item
+  to the chunk btree;
+
+* When removing a device (ioctl), where we need to remove a device item
+  from the chunk btree;
+
+* When resizing a device (ioctl), where we need to update a device item in
+  the chunk btree and may need to relocate a system chunk that lies beyond
+  the new device size when shrinking a device.
+
+The problem happens due to a sequence of steps like the following:
+
+1) Task A starts a data or metadata chunk allocation and it locks the
+   chunk mutex;
+
+2) Task B is relocating a system chunk, and when it needs to COW an extent
+   buffer of the chunk btree, it has locked both that extent buffer as
+   well as its parent extent buffer;
+
+3) Since there is not enough available system space, either because none
+   of the existing system block groups have enough free space or because
+   the only one with enough free space is in RO mode due to the relocation,
+   task B triggers a new system chunk allocation. It blocks when trying to
+   acquire the chunk mutex, currently held by task A;
+
+4) Task A enters btrfs_chunk_alloc_add_chunk_item(), in order to insert
+   the new chunk item into the chunk btree and update the existing device
+   items there. But in order to do that, it has to lock the extent buffer
+   that task B locked at step 2, or its parent extent buffer, but task B
+   is waiting on the chunk mutex, which is currently locked by task A,
+   therefore resulting in a deadlock.
+
+One example report when the deadlock happens with system chunk relocation:
+
+  INFO: task kworker/u9:5:546 blocked for more than 143 seconds.
+        Not tainted 5.15.0-rc3+ #1
+  "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+  task:kworker/u9:5    state:D stack:25936 pid:  546 ppid:     2 flags:0x00004000
+  Workqueue: events_unbound btrfs_async_reclaim_metadata_space
+  Call Trace:
+   context_switch kernel/sched/core.c:4940 [inline]
+   __schedule+0xcd9/0x2530 kernel/sched/core.c:6287
+   schedule+0xd3/0x270 kernel/sched/core.c:6366
+   rwsem_down_read_slowpath+0x4ee/0x9d0 kernel/locking/rwsem.c:993
+   __down_read_common kernel/locking/rwsem.c:1214 [inline]
+   __down_read kernel/locking/rwsem.c:1223 [inline]
+   down_read_nested+0xe6/0x440 kernel/locking/rwsem.c:1590
+   __btrfs_tree_read_lock+0x31/0x350 fs/btrfs/locking.c:47
+   btrfs_tree_read_lock fs/btrfs/locking.c:54 [inline]
+   btrfs_read_lock_root_node+0x8a/0x320 fs/btrfs/locking.c:191
+   btrfs_search_slot_get_root fs/btrfs/ctree.c:1623 [inline]
+   btrfs_search_slot+0x13b4/0x2140 fs/btrfs/ctree.c:1728
+   btrfs_update_device+0x11f/0x500 fs/btrfs/volumes.c:2794
+   btrfs_chunk_alloc_add_chunk_item+0x34d/0xea0 fs/btrfs/volumes.c:5504
+   do_chunk_alloc fs/btrfs/block-group.c:3408 [inline]
+   btrfs_chunk_alloc+0x84d/0xf50 fs/btrfs/block-group.c:3653
+   flush_space+0x54e/0xd80 fs/btrfs/space-info.c:670
+   btrfs_async_reclaim_metadata_space+0x396/0xa90 fs/btrfs/space-info.c:953
+   process_one_work+0x9df/0x16d0 kernel/workqueue.c:2297
+   worker_thread+0x90/0xed0 kernel/workqueue.c:2444
+   kthread+0x3e5/0x4d0 kernel/kthread.c:319
+   ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295
+  INFO: task syz-executor:9107 blocked for more than 143 seconds.
+        Not tainted 5.15.0-rc3+ #1
+  "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+  task:syz-executor    state:D stack:23200 pid: 9107 ppid:  7792 flags:0x00004004
+  Call Trace:
+   context_switch kernel/sched/core.c:4940 [inline]
+   __schedule+0xcd9/0x2530 kernel/sched/core.c:6287
+   schedule+0xd3/0x270 kernel/sched/core.c:6366
+   schedule_preempt_disabled+0xf/0x20 kernel/sched/core.c:6425
+   __mutex_lock_common kernel/locking/mutex.c:669 [inline]
+   __mutex_lock+0xc96/0x1680 kernel/locking/mutex.c:729
+   btrfs_chunk_alloc+0x31a/0xf50 fs/btrfs/block-group.c:3631
+   find_free_extent_update_loop fs/btrfs/extent-tree.c:3986 [inline]
+   find_free_extent+0x25cb/0x3a30 fs/btrfs/extent-tree.c:4335
+   btrfs_reserve_extent+0x1f1/0x500 fs/btrfs/extent-tree.c:4415
+   btrfs_alloc_tree_block+0x203/0x1120 fs/btrfs/extent-tree.c:4813
+   __btrfs_cow_block+0x412/0x1620 fs/btrfs/ctree.c:415
+   btrfs_cow_block+0x2f6/0x8c0 fs/btrfs/ctree.c:570
+   btrfs_search_slot+0x1094/0x2140 fs/btrfs/ctree.c:1768
+   relocate_tree_block fs/btrfs/relocation.c:2694 [inline]
+   relocate_tree_blocks+0xf73/0x1770 fs/btrfs/relocation.c:2757
+   relocate_block_group+0x47e/0xc70 fs/btrfs/relocation.c:3673
+   btrfs_relocate_block_group+0x48a/0xc60 fs/btrfs/relocation.c:4070
+   btrfs_relocate_chunk+0x96/0x280 fs/btrfs/volumes.c:3181
+   __btrfs_balance fs/btrfs/volumes.c:3911 [inline]
+   btrfs_balance+0x1f03/0x3cd0 fs/btrfs/volumes.c:4301
+   btrfs_ioctl_balance+0x61e/0x800 fs/btrfs/ioctl.c:4137
+   btrfs_ioctl+0x39ea/0x7b70 fs/btrfs/ioctl.c:4949
+   vfs_ioctl fs/ioctl.c:51 [inline]
+   __do_sys_ioctl fs/ioctl.c:874 [inline]
+   __se_sys_ioctl fs/ioctl.c:860 [inline]
+   __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860
+   do_syscall_x64 arch/x86/entry/common.c:50 [inline]
+   do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80
+   entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+So fix this by making sure that whenever we try to modify the chunk btree
+and we are neither in a chunk allocation context nor in a chunk remove
+context, we reserve system space before modifying the chunk btree.
+
+Reported-by: Hao Sun <sunhao.th@gmail.com>
+Link: https://lore.kernel.org/linux-btrfs/CACkBjsax51i4mu6C0C3vJqQN3NR_iVuucoeG3U1HXjrgzn5FFQ@mail.gmail.com/
+Fixes: 79bd37120b1495 ("btrfs: rework chunk allocation to avoid exhaustion of the system chunk array")
+CC: stable@vger.kernel.org # 5.14+
+Reviewed-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/block-group.c | 146 +++++++++++++++++++++++++----------------
+ fs/btrfs/block-group.h |   2 +
+ fs/btrfs/relocation.c  |   4 ++
+ fs/btrfs/volumes.c     |  15 ++++-
+ 4 files changed, 111 insertions(+), 56 deletions(-)
+
+diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
+index aadc1203ad88..c6c5a22ff6e8 100644
+--- a/fs/btrfs/block-group.c
++++ b/fs/btrfs/block-group.c
+@@ -3406,25 +3406,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
+               goto out;
+       }
+-      /*
+-       * If this is a system chunk allocation then stop right here and do not
+-       * add the chunk item to the chunk btree. This is to prevent a deadlock
+-       * because this system chunk allocation can be triggered while COWing
+-       * some extent buffer of the chunk btree and while holding a lock on a
+-       * parent extent buffer, in which case attempting to insert the chunk
+-       * item (or update the device item) would result in a deadlock on that
+-       * parent extent buffer. In this case defer the chunk btree updates to
+-       * the second phase of chunk allocation and keep our reservation until
+-       * the second phase completes.
+-       *
+-       * This is a rare case and can only be triggered by the very few cases
+-       * we have where we need to touch the chunk btree outside chunk allocation
+-       * and chunk removal. These cases are basically adding a device, removing
+-       * a device or resizing a device.
+-       */
+-      if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+-              return 0;
+-
+       ret = btrfs_chunk_alloc_add_chunk_item(trans, bg);
+       /*
+        * Normally we are not expected to fail with -ENOSPC here, since we have
+@@ -3557,14 +3538,14 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
+  * This has happened before and commit eafa4fd0ad0607 ("btrfs: fix exhaustion of
+  * the system chunk array due to concurrent allocations") provides more details.
+  *
+- * For allocation of system chunks, we defer the updates and insertions into the
+- * chunk btree to phase 2. This is to prevent deadlocks on extent buffers because
+- * if the chunk allocation is triggered while COWing an extent buffer of the
+- * chunk btree, we are holding a lock on the parent of that extent buffer and
+- * doing the chunk btree updates and insertions can require locking that parent.
+- * This is for the very few and rare cases where we update the chunk btree that
+- * are not chunk allocation or chunk removal: adding a device, removing a device
+- * or resizing a device.
++ * Allocation of system chunks does not happen through this function. A task that
++ * needs to update the chunk btree (the only btree that uses system chunks), must
++ * preallocate chunk space by calling either check_system_chunk() or
++ * btrfs_reserve_chunk_metadata() - the former is used when allocating a data or
++ * metadata chunk or when removing a chunk, while the later is used before doing
++ * a modification to the chunk btree - use cases for the later are adding,
++ * removing and resizing a device as well as relocation of a system chunk.
++ * See the comment below for more details.
+  *
+  * The reservation of system space, done through check_system_chunk(), as well
+  * as all the updates and insertions into the chunk btree must be done while
+@@ -3601,11 +3582,27 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
+       if (trans->allocating_chunk)
+               return -ENOSPC;
+       /*
+-       * If we are removing a chunk, don't re-enter or we would deadlock.
+-       * System space reservation and system chunk allocation is done by the
+-       * chunk remove operation (btrfs_remove_chunk()).
++       * Allocation of system chunks can not happen through this path, as we
++       * could end up in a deadlock if we are allocating a data or metadata
++       * chunk and there is another task modifying the chunk btree.
++       *
++       * This is because while we are holding the chunk mutex, we will attempt
++       * to add the new chunk item to the chunk btree or update an existing
++       * device item in the chunk btree, while the other task that is modifying
++       * the chunk btree is attempting to COW an extent buffer while holding a
++       * lock on it and on its parent - if the COW operation triggers a system
++       * chunk allocation, then we can deadlock because we are holding the
++       * chunk mutex and we may need to access that extent buffer or its parent
++       * in order to add the chunk item or update a device item.
++       *
++       * Tasks that want to modify the chunk tree should reserve system space
++       * before updating the chunk btree, by calling either
++       * btrfs_reserve_chunk_metadata() or check_system_chunk().
++       * It's possible that after a task reserves the space, it still ends up
++       * here - this happens in the cases described above at do_chunk_alloc().
++       * The task will have to either retry or fail.
+        */
+-      if (trans->removing_chunk)
++      if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+               return -ENOSPC;
+       space_info = btrfs_find_space_info(fs_info, flags);
+@@ -3704,17 +3701,14 @@ static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type)
+       return num_dev;
+ }
+-/*
+- * Reserve space in the system space for allocating or removing a chunk
+- */
+-void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
++static void reserve_chunk_space(struct btrfs_trans_handle *trans,
++                              u64 bytes,
++                              u64 type)
+ {
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_space_info *info;
+       u64 left;
+-      u64 thresh;
+       int ret = 0;
+-      u64 num_devs;
+       /*
+        * Needed because we can end up allocating a system chunk and for an
+@@ -3727,19 +3721,13 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+       left = info->total_bytes - btrfs_space_info_used(info, true);
+       spin_unlock(&info->lock);
+-      num_devs = get_profile_num_devs(fs_info, type);
+-
+-      /* num_devs device items to update and 1 chunk item to add or remove */
+-      thresh = btrfs_calc_metadata_size(fs_info, num_devs) +
+-              btrfs_calc_insert_metadata_size(fs_info, 1);
+-
+-      if (left < thresh && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
++      if (left < bytes && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
+               btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",
+-                         left, thresh, type);
++                         left, bytes, type);
+               btrfs_dump_space_info(fs_info, info, 0, 0);
+       }
+-      if (left < thresh) {
++      if (left < bytes) {
+               u64 flags = btrfs_system_alloc_profile(fs_info);
+               struct btrfs_block_group *bg;
+@@ -3748,21 +3736,20 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+                * needing it, as we might not need to COW all nodes/leafs from
+                * the paths we visit in the chunk tree (they were already COWed
+                * or created in the current transaction for example).
+-               *
+-               * Also, if our caller is allocating a system chunk, do not
+-               * attempt to insert the chunk item in the chunk btree, as we
+-               * could deadlock on an extent buffer since our caller may be
+-               * COWing an extent buffer from the chunk btree.
+                */
+               bg = btrfs_create_chunk(trans, flags);
+               if (IS_ERR(bg)) {
+                       ret = PTR_ERR(bg);
+-              } else if (!(type & BTRFS_BLOCK_GROUP_SYSTEM)) {
++              } else {
+                       /*
+                        * If we fail to add the chunk item here, we end up
+                        * trying again at phase 2 of chunk allocation, at
+                        * btrfs_create_pending_block_groups(). So ignore
+-                       * any error here.
++                       * any error here. An ENOSPC here could happen, due to
++                       * the cases described at do_chunk_alloc() - the system
++                       * block group we just created was just turned into RO
++                       * mode by a scrub for example, or a running discard
++                       * temporarily removed its free space entries, etc.
+                        */
+                       btrfs_chunk_alloc_add_chunk_item(trans, bg);
+               }
+@@ -3771,12 +3758,61 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+       if (!ret) {
+               ret = btrfs_block_rsv_add(fs_info->chunk_root,
+                                         &fs_info->chunk_block_rsv,
+-                                        thresh, BTRFS_RESERVE_NO_FLUSH);
++                                        bytes, BTRFS_RESERVE_NO_FLUSH);
+               if (!ret)
+-                      trans->chunk_bytes_reserved += thresh;
++                      trans->chunk_bytes_reserved += bytes;
+       }
+ }
++/*
++ * Reserve space in the system space for allocating or removing a chunk.
++ * The caller must be holding fs_info->chunk_mutex.
++ */
++void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
++{
++      struct btrfs_fs_info *fs_info = trans->fs_info;
++      const u64 num_devs = get_profile_num_devs(fs_info, type);
++      u64 bytes;
++
++      /* num_devs device items to update and 1 chunk item to add or remove. */
++      bytes = btrfs_calc_metadata_size(fs_info, num_devs) +
++              btrfs_calc_insert_metadata_size(fs_info, 1);
++
++      reserve_chunk_space(trans, bytes, type);
++}
++
++/*
++ * Reserve space in the system space, if needed, for doing a modification to the
++ * chunk btree.
++ *
++ * @trans:            A transaction handle.
++ * @is_item_insertion:        Indicate if the modification is for inserting a new item
++ *                    in the chunk btree or if it's for the deletion or update
++ *                    of an existing item.
++ *
++ * This is used in a context where we need to update the chunk btree outside
++ * block group allocation and removal, to avoid a deadlock with a concurrent
++ * task that is allocating a metadata or data block group and therefore needs to
++ * update the chunk btree while holding the chunk mutex. After the update to the
++ * chunk btree is done, btrfs_trans_release_chunk_metadata() should be called.
++ *
++ */
++void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans,
++                                bool is_item_insertion)
++{
++      struct btrfs_fs_info *fs_info = trans->fs_info;
++      u64 bytes;
++
++      if (is_item_insertion)
++              bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
++      else
++              bytes = btrfs_calc_metadata_size(fs_info, 1);
++
++      mutex_lock(&fs_info->chunk_mutex);
++      reserve_chunk_space(trans, bytes, BTRFS_BLOCK_GROUP_SYSTEM);
++      mutex_unlock(&fs_info->chunk_mutex);
++}
++
+ void btrfs_put_block_group_cache(struct btrfs_fs_info *info)
+ {
+       struct btrfs_block_group *block_group;
+diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
+index c72a71efcb18..37e55ebde735 100644
+--- a/fs/btrfs/block-group.h
++++ b/fs/btrfs/block-group.h
+@@ -289,6 +289,8 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
+                     enum btrfs_chunk_alloc_enum force);
+ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type);
+ void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type);
++void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans,
++                                bool is_item_insertion);
+ u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags);
+ void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
+ int btrfs_free_block_groups(struct btrfs_fs_info *info);
+diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
+index 0300770c0a89..429a198f8937 100644
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -2698,8 +2698,12 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
+                       list_add_tail(&node->list, &rc->backref_cache.changed);
+               } else {
+                       path->lowest_level = node->level;
++                      if (root == root->fs_info->chunk_root)
++                              btrfs_reserve_chunk_metadata(trans, false);
+                       ret = btrfs_search_slot(trans, root, key, path, 0, 1);
+                       btrfs_release_path(path);
++                      if (root == root->fs_info->chunk_root)
++                              btrfs_trans_release_chunk_metadata(trans);
+                       if (ret > 0)
+                               ret = 0;
+               }
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index b75ce79a2540..fa68efd7e610 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1879,8 +1879,10 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans,
+       key.type = BTRFS_DEV_ITEM_KEY;
+       key.offset = device->devid;
++      btrfs_reserve_chunk_metadata(trans, true);
+       ret = btrfs_insert_empty_item(trans, trans->fs_info->chunk_root, path,
+                                     &key, sizeof(*dev_item));
++      btrfs_trans_release_chunk_metadata(trans);
+       if (ret)
+               goto out;
+@@ -1957,7 +1959,9 @@ static int btrfs_rm_dev_item(struct btrfs_device *device)
+       key.type = BTRFS_DEV_ITEM_KEY;
+       key.offset = device->devid;
++      btrfs_reserve_chunk_metadata(trans, false);
+       ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
++      btrfs_trans_release_chunk_metadata(trans);
+       if (ret) {
+               if (ret > 0)
+                       ret = -ENOENT;
+@@ -2513,7 +2517,9 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+       key.type = BTRFS_DEV_ITEM_KEY;
+       while (1) {
++              btrfs_reserve_chunk_metadata(trans, false);
+               ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
++              btrfs_trans_release_chunk_metadata(trans);
+               if (ret < 0)
+                       goto error;
+@@ -2861,6 +2867,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
+       struct btrfs_super_block *super_copy = fs_info->super_copy;
+       u64 old_total;
+       u64 diff;
++      int ret;
+       if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
+               return -EACCES;
+@@ -2889,7 +2896,11 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
+                             &trans->transaction->dev_update_list);
+       mutex_unlock(&fs_info->chunk_mutex);
+-      return btrfs_update_device(trans, device);
++      btrfs_reserve_chunk_metadata(trans, false);
++      ret = btrfs_update_device(trans, device);
++      btrfs_trans_release_chunk_metadata(trans);
++
++      return ret;
+ }
+ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
+@@ -4926,8 +4937,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
+                       round_down(old_total - diff, fs_info->sectorsize));
+       mutex_unlock(&fs_info->chunk_mutex);
++      btrfs_reserve_chunk_metadata(trans, false);
+       /* Now btrfs_update_device() will change the on-disk size. */
+       ret = btrfs_update_device(trans, device);
++      btrfs_trans_release_chunk_metadata(trans);
+       if (ret < 0) {
+               btrfs_abort_transaction(trans, ret);
+               btrfs_end_transaction(trans);
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch b/queue-5.15/btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch
new file mode 100644 (file)
index 0000000..494a096
--- /dev/null
@@ -0,0 +1,309 @@
+From 56d47ae9013f457ccbf4a4af691c9178a9822e25 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Dec 2021 08:45:12 +0000
+Subject: btrfs: fix invalid delayed ref after subvolume creation failure
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 7a1636089acfee7562fe79aff7d1b4c57869896d ]
+
+When creating a subvolume, at ioctl.c:create_subvol(), if we fail to
+insert the new root's root item into the root tree, we are freeing the
+metadata extent we reserved for the new root to prevent a metadata
+extent leak, as we don't abort the transaction at that point (since
+there is nothing at that point that is irreversible).
+
+However we allocated the metadata extent for the new root which we are
+creating for the new subvolume, so its delayed reference refers to the
+ID of this new root. But when we free the metadata extent we pass the
+root of the subvolume where the new subvolume is located to
+btrfs_free_tree_block() - this is incorrect because this will generate
+a delayed reference that refers to the ID of the parent subvolume's root,
+and not to ID of the new root.
+
+This results in a failure when running delayed references that leads to
+a transaction abort and a trace like the following:
+
+[3868.738042] RIP: 0010:__btrfs_free_extent+0x709/0x950 [btrfs]
+[3868.739857] Code: 68 0f 85 e6 fb ff (...)
+[3868.742963] RSP: 0018:ffffb0e9045cf910 EFLAGS: 00010246
+[3868.743908] RAX: 00000000fffffffe RBX: 00000000fffffffe RCX: 0000000000000002
+[3868.745312] RDX: 00000000fffffffe RSI: 0000000000000002 RDI: ffff90b0cd793b88
+[3868.746643] RBP: 000000000e5d8000 R08: 0000000000000000 R09: ffff90b0cd793b88
+[3868.747979] R10: 0000000000000002 R11: 00014ded97944d68 R12: 0000000000000000
+[3868.749373] R13: ffff90b09afe4a28 R14: 0000000000000000 R15: ffff90b0cd793b88
+[3868.750725] FS:  00007f281c4a8b80(0000) GS:ffff90b3ada00000(0000) knlGS:0000000000000000
+[3868.752275] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[3868.753515] CR2: 00007f281c6a5000 CR3: 0000000108a42006 CR4: 0000000000370ee0
+[3868.754869] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[3868.756228] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+[3868.757803] Call Trace:
+[3868.758281]  <TASK>
+[3868.758655]  ? btrfs_merge_delayed_refs+0x178/0x1c0 [btrfs]
+[3868.759827]  __btrfs_run_delayed_refs+0x2b1/0x1250 [btrfs]
+[3868.761047]  btrfs_run_delayed_refs+0x86/0x210 [btrfs]
+[3868.762069]  ? lock_acquired+0x19f/0x420
+[3868.762829]  btrfs_commit_transaction+0x69/0xb20 [btrfs]
+[3868.763860]  ? _raw_spin_unlock+0x29/0x40
+[3868.764614]  ? btrfs_block_rsv_release+0x1c2/0x1e0 [btrfs]
+[3868.765870]  create_subvol+0x1d8/0x9a0 [btrfs]
+[3868.766766]  btrfs_mksubvol+0x447/0x4c0 [btrfs]
+[3868.767669]  ? preempt_count_add+0x49/0xa0
+[3868.768444]  __btrfs_ioctl_snap_create+0x123/0x190 [btrfs]
+[3868.769639]  ? _copy_from_user+0x66/0xa0
+[3868.770391]  btrfs_ioctl_snap_create_v2+0xbb/0x140 [btrfs]
+[3868.771495]  btrfs_ioctl+0xd1e/0x35c0 [btrfs]
+[3868.772364]  ? __slab_free+0x10a/0x360
+[3868.773198]  ? rcu_read_lock_sched_held+0x12/0x60
+[3868.774121]  ? lock_release+0x223/0x4a0
+[3868.774863]  ? lock_acquired+0x19f/0x420
+[3868.775634]  ? rcu_read_lock_sched_held+0x12/0x60
+[3868.776530]  ? trace_hardirqs_on+0x1b/0xe0
+[3868.777373]  ? _raw_spin_unlock_irqrestore+0x3e/0x60
+[3868.778280]  ? kmem_cache_free+0x321/0x3c0
+[3868.779011]  ? __x64_sys_ioctl+0x83/0xb0
+[3868.779718]  __x64_sys_ioctl+0x83/0xb0
+[3868.780387]  do_syscall_64+0x3b/0xc0
+[3868.781059]  entry_SYSCALL_64_after_hwframe+0x44/0xae
+[3868.781953] RIP: 0033:0x7f281c59e957
+[3868.782585] Code: 3c 1c 48 f7 d8 4c (...)
+[3868.785867] RSP: 002b:00007ffe1f83e2b8 EFLAGS: 00000202 ORIG_RAX: 0000000000000010
+[3868.787198] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f281c59e957
+[3868.788450] RDX: 00007ffe1f83e2c0 RSI: 0000000050009418 RDI: 0000000000000003
+[3868.789748] RBP: 00007ffe1f83f300 R08: 0000000000000000 R09: 00007ffe1f83fe36
+[3868.791214] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000003
+[3868.792468] R13: 0000000000000003 R14: 00007ffe1f83e2c0 R15: 00000000000003cc
+[3868.793765]  </TASK>
+[3868.794037] irq event stamp: 0
+[3868.794548] hardirqs last  enabled at (0): [<0000000000000000>] 0x0
+[3868.795670] hardirqs last disabled at (0): [<ffffffff98294214>] copy_process+0x934/0x2040
+[3868.797086] softirqs last  enabled at (0): [<ffffffff98294214>] copy_process+0x934/0x2040
+[3868.798309] softirqs last disabled at (0): [<0000000000000000>] 0x0
+[3868.799284] ---[ end trace be24c7002fe27747 ]---
+[3868.799928] BTRFS info (device dm-0): leaf 241188864 gen 1268 total ptrs 214 free space 469 owner 2
+[3868.801133] BTRFS info (device dm-0): refs 2 lock_owner 225627 current 225627
+[3868.802056]  item 0 key (237436928 169 0) itemoff 16250 itemsize 33
+[3868.802863]          extent refs 1 gen 1265 flags 2
+[3868.803447]          ref#0: tree block backref root 1610
+(...)
+[3869.064354]  item 114 key (241008640 169 0) itemoff 12488 itemsize 33
+[3869.065421]          extent refs 1 gen 1268 flags 2
+[3869.066115]          ref#0: tree block backref root 1689
+(...)
+[3869.403834] BTRFS error (device dm-0): unable to find ref byte nr 241008640 parent 0 root 1622  owner 0 offset 0
+[3869.405641] BTRFS: error (device dm-0) in __btrfs_free_extent:3076: errno=-2 No such entry
+[3869.407138] BTRFS: error (device dm-0) in btrfs_run_delayed_refs:2159: errno=-2 No such entry
+
+Fix this by passing the new subvolume's root ID to btrfs_free_tree_block().
+This requires changing the root argument of btrfs_free_tree_block() from
+struct btrfs_root * to a u64, since at this point during the subvolume
+creation we have not yet created the struct btrfs_root for the new
+subvolume, and btrfs_free_tree_block() only needs a root ID and nothing
+else from a struct btrfs_root.
+
+This was triggered by test case generic/475 from fstests.
+
+Fixes: 67addf29004c5b ("btrfs: fix metadata extent leak after failure to create subvolume")
+CC: stable@vger.kernel.org # 4.4+
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ctree.c           | 17 +++++++++--------
+ fs/btrfs/ctree.h           |  7 ++++++-
+ fs/btrfs/extent-tree.c     | 13 +++++++------
+ fs/btrfs/free-space-tree.c |  4 ++--
+ fs/btrfs/ioctl.c           |  9 +++++----
+ fs/btrfs/qgroup.c          |  3 ++-
+ 6 files changed, 31 insertions(+), 22 deletions(-)
+
+diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
+index 899f85445925..341ce90d24b1 100644
+--- a/fs/btrfs/ctree.c
++++ b/fs/btrfs/ctree.c
+@@ -462,8 +462,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
+               BUG_ON(ret < 0);
+               rcu_assign_pointer(root->node, cow);
+-              btrfs_free_tree_block(trans, root, buf, parent_start,
+-                                    last_ref);
++              btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
++                                    parent_start, last_ref);
+               free_extent_buffer(buf);
+               add_root_to_dirty_list(root);
+       } else {
+@@ -484,8 +484,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
+                               return ret;
+                       }
+               }
+-              btrfs_free_tree_block(trans, root, buf, parent_start,
+-                                    last_ref);
++              btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
++                                    parent_start, last_ref);
+       }
+       if (unlock_orig)
+               btrfs_tree_unlock(buf);
+@@ -926,7 +926,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
+               free_extent_buffer(mid);
+               root_sub_used(root, mid->len);
+-              btrfs_free_tree_block(trans, root, mid, 0, 1);
++              btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+               /* once for the root ptr */
+               free_extent_buffer_stale(mid);
+               return 0;
+@@ -985,7 +985,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
+                       btrfs_tree_unlock(right);
+                       del_ptr(root, path, level + 1, pslot + 1);
+                       root_sub_used(root, right->len);
+-                      btrfs_free_tree_block(trans, root, right, 0, 1);
++                      btrfs_free_tree_block(trans, btrfs_root_id(root), right,
++                                            0, 1);
+                       free_extent_buffer_stale(right);
+                       right = NULL;
+               } else {
+@@ -1030,7 +1031,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
+               btrfs_tree_unlock(mid);
+               del_ptr(root, path, level + 1, pslot);
+               root_sub_used(root, mid->len);
+-              btrfs_free_tree_block(trans, root, mid, 0, 1);
++              btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+               free_extent_buffer_stale(mid);
+               mid = NULL;
+       } else {
+@@ -4059,7 +4060,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
+       root_sub_used(root, leaf->len);
+       atomic_inc(&leaf->refs);
+-      btrfs_free_tree_block(trans, root, leaf, 0, 1);
++      btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
+       free_extent_buffer_stale(leaf);
+ }
+ /*
+diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
+index 21c44846b002..cc72d8981c47 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -2256,6 +2256,11 @@ static inline bool btrfs_root_dead(const struct btrfs_root *root)
+       return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
+ }
++static inline u64 btrfs_root_id(const struct btrfs_root *root)
++{
++      return root->root_key.objectid;
++}
++
+ /* struct btrfs_root_backup */
+ BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
+                  tree_root, 64);
+@@ -2718,7 +2723,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+                                            u64 empty_size,
+                                            enum btrfs_lock_nesting nest);
+ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+-                         struct btrfs_root *root,
++                         u64 root_id,
+                          struct extent_buffer *buf,
+                          u64 parent, int last_ref);
+ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
+diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
+index e01b9344fb9c..f11616f61dd6 100644
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -3280,20 +3280,20 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
+ }
+ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+-                         struct btrfs_root *root,
++                         u64 root_id,
+                          struct extent_buffer *buf,
+                          u64 parent, int last_ref)
+ {
+-      struct btrfs_fs_info *fs_info = root->fs_info;
++      struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_ref generic_ref = { 0 };
+       int ret;
+       btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
+                              buf->start, buf->len, parent);
+       btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
+-                          root->root_key.objectid, 0, false);
++                          root_id, 0, false);
+-      if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
++      if (root_id != BTRFS_TREE_LOG_OBJECTID) {
+               btrfs_ref_tree_mod(fs_info, &generic_ref);
+               ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL);
+               BUG_ON(ret); /* -ENOMEM */
+@@ -3303,7 +3303,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+               struct btrfs_block_group *cache;
+               bool must_pin = false;
+-              if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
++              if (root_id != BTRFS_TREE_LOG_OBJECTID) {
+                       ret = check_ref_cleanup(trans, buf->start);
+                       if (!ret) {
+                               btrfs_redirty_list_add(trans->transaction, buf);
+@@ -5441,7 +5441,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
+                       goto owner_mismatch;
+       }
+-      btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
++      btrfs_free_tree_block(trans, btrfs_root_id(root), eb, parent,
++                            wc->refs[level] == 1);
+ out:
+       wc->refs[level] = 0;
+       wc->flags[level] = 0;
+diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
+index a33bca94d133..3abec44c6255 100644
+--- a/fs/btrfs/free-space-tree.c
++++ b/fs/btrfs/free-space-tree.c
+@@ -1256,8 +1256,8 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
+       btrfs_tree_lock(free_space_root->node);
+       btrfs_clean_tree_block(free_space_root->node);
+       btrfs_tree_unlock(free_space_root->node);
+-      btrfs_free_tree_block(trans, free_space_root, free_space_root->node,
+-                            0, 1);
++      btrfs_free_tree_block(trans, btrfs_root_id(free_space_root),
++                            free_space_root->node, 0, 1);
+       btrfs_put_root(free_space_root);
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index bf53af8694f8..7272d9d3fa78 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -615,11 +615,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
+                * Since we don't abort the transaction in this case, free the
+                * tree block so that we don't leak space and leave the
+                * filesystem in an inconsistent state (an extent item in the
+-               * extent tree without backreferences). Also no need to have
+-               * the tree block locked since it is not in any tree at this
+-               * point, so no other task can find it and use it.
++               * extent tree with a backreference for a root that does not
++               * exists). Also no need to have the tree block locked since it
++               * is not in any tree at this point, so no other task can find
++               * it and use it.
+                */
+-              btrfs_free_tree_block(trans, root, leaf, 0, 1);
++              btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
+               free_extent_buffer(leaf);
+               goto fail;
+       }
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index 2c803108ea94..4ca809fa80ea 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1259,7 +1259,8 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+       btrfs_tree_lock(quota_root->node);
+       btrfs_clean_tree_block(quota_root->node);
+       btrfs_tree_unlock(quota_root->node);
+-      btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1);
++      btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
++                            quota_root->node, 0, 1);
+       btrfs_put_root(quota_root);
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch b/queue-5.15/btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch
new file mode 100644 (file)
index 0000000..5e32c2a
--- /dev/null
@@ -0,0 +1,93 @@
+From 84eb7d5cd410d040729f253c7db28d766ddf3fd5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Dec 2021 08:45:13 +0000
+Subject: btrfs: fix warning when freeing leaf after subvolume creation failure
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 212a58fda9b9077e0efc20200a4feb76afacfd95 ]
+
+When creating a subvolume, at ioctl.c:create_subvol(), if we fail to
+insert the root item for the new subvolume into the root tree, we can
+trigger the following warning:
+
+[78961.741046] WARNING: CPU: 0 PID: 4079814 at fs/btrfs/extent-tree.c:3357 btrfs_free_tree_block+0x2af/0x310 [btrfs]
+[78961.743344] Modules linked in:
+[78961.749440]  dm_snapshot dm_thin_pool (...)
+[78961.773648] CPU: 0 PID: 4079814 Comm: fsstress Not tainted 5.16.0-rc4-btrfs-next-108 #1
+[78961.775198] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
+[78961.777266] RIP: 0010:btrfs_free_tree_block+0x2af/0x310 [btrfs]
+[78961.778398] Code: 17 00 48 85 (...)
+[78961.781067] RSP: 0018:ffffaa4001657b28 EFLAGS: 00010202
+[78961.781877] RAX: 0000000000000213 RBX: ffff897f8a796910 RCX: 0000000000000000
+[78961.782780] RDX: 0000000000000000 RSI: 0000000011004000 RDI: 00000000ffffffff
+[78961.783764] RBP: ffff8981f490e800 R08: 0000000000000001 R09: 0000000000000000
+[78961.784740] R10: 0000000000000000 R11: 0000000000000001 R12: ffff897fc963fcc8
+[78961.785665] R13: 0000000000000001 R14: ffff898063548000 R15: ffff898063548000
+[78961.786620] FS:  00007f31283c6b80(0000) GS:ffff8982ace00000(0000) knlGS:0000000000000000
+[78961.787717] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[78961.788598] CR2: 00007f31285c3000 CR3: 000000023fcc8003 CR4: 0000000000370ef0
+[78961.789568] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[78961.790585] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+[78961.791684] Call Trace:
+[78961.792082]  <TASK>
+[78961.792359]  create_subvol+0x5d1/0x9a0 [btrfs]
+[78961.793054]  btrfs_mksubvol+0x447/0x4c0 [btrfs]
+[78961.794009]  ? preempt_count_add+0x49/0xa0
+[78961.794705]  __btrfs_ioctl_snap_create+0x123/0x190 [btrfs]
+[78961.795712]  ? _copy_from_user+0x66/0xa0
+[78961.796382]  btrfs_ioctl_snap_create_v2+0xbb/0x140 [btrfs]
+[78961.797392]  btrfs_ioctl+0xd1e/0x35c0 [btrfs]
+[78961.798172]  ? __slab_free+0x10a/0x360
+[78961.798820]  ? rcu_read_lock_sched_held+0x12/0x60
+[78961.799664]  ? lock_release+0x223/0x4a0
+[78961.800321]  ? lock_acquired+0x19f/0x420
+[78961.800992]  ? rcu_read_lock_sched_held+0x12/0x60
+[78961.801796]  ? trace_hardirqs_on+0x1b/0xe0
+[78961.802495]  ? _raw_spin_unlock_irqrestore+0x3e/0x60
+[78961.803358]  ? kmem_cache_free+0x321/0x3c0
+[78961.804071]  ? __x64_sys_ioctl+0x83/0xb0
+[78961.804711]  __x64_sys_ioctl+0x83/0xb0
+[78961.805348]  do_syscall_64+0x3b/0xc0
+[78961.805969]  entry_SYSCALL_64_after_hwframe+0x44/0xae
+[78961.806830] RIP: 0033:0x7f31284bc957
+[78961.807517] Code: 3c 1c 48 f7 d8 (...)
+
+This is because we are calling btrfs_free_tree_block() on an extent
+buffer that is dirty. Fix that by cleaning the extent buffer, with
+btrfs_clean_tree_block(), before freeing it.
+
+This was triggered by test case generic/475 from fstests.
+
+Fixes: 67addf29004c5b ("btrfs: fix metadata extent leak after failure to create subvolume")
+CC: stable@vger.kernel.org # 4.4+
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ioctl.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index 7272d9d3fa78..a37ab3e89a3b 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -616,10 +616,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
+                * tree block so that we don't leak space and leave the
+                * filesystem in an inconsistent state (an extent item in the
+                * extent tree with a backreference for a root that does not
+-               * exists). Also no need to have the tree block locked since it
+-               * is not in any tree at this point, so no other task can find
+-               * it and use it.
++               * exists).
+                */
++              btrfs_tree_lock(leaf);
++              btrfs_clean_tree_block(leaf);
++              btrfs_tree_unlock(leaf);
+               btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
+               free_extent_buffer(leaf);
+               goto fail;
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch b/queue-5.15/btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch
new file mode 100644 (file)
index 0000000..bed127f
--- /dev/null
@@ -0,0 +1,486 @@
+From 163b3fa489aa076300b8e702f4b810ef963ac947 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Oct 2021 16:12:42 -0400
+Subject: btrfs: handle device lookup with btrfs_dev_lookup_args
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+[ Upstream commit 562d7b1512f7369a19bca2883e2e8672d78f0481 ]
+
+We have a lot of device lookup functions that all do something slightly
+different.  Clean this up by adding a struct to hold the different
+lookup criteria, and then pass this around to btrfs_find_device() so it
+can do the proper matching based on the lookup criteria.
+
+Reviewed-by: Anand Jain <anand.jain@oracle.com>
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/dev-replace.c |  16 +++---
+ fs/btrfs/ioctl.c       |  13 +++--
+ fs/btrfs/scrub.c       |   6 +-
+ fs/btrfs/volumes.c     | 122 +++++++++++++++++++++++++----------------
+ fs/btrfs/volumes.h     |  20 ++++++-
+ 5 files changed, 112 insertions(+), 65 deletions(-)
+
+diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
+index bdbc310a8f8c..781556e2a37f 100644
+--- a/fs/btrfs/dev-replace.c
++++ b/fs/btrfs/dev-replace.c
+@@ -70,6 +70,7 @@ static int btrfs_dev_replace_kthread(void *data);
+ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
+ {
++      struct btrfs_dev_lookup_args args = { .devid = BTRFS_DEV_REPLACE_DEVID };
+       struct btrfs_key key;
+       struct btrfs_root *dev_root = fs_info->dev_root;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+@@ -100,8 +101,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
+                * We don't have a replace item or it's corrupted.  If there is
+                * a replace target, fail the mount.
+                */
+-              if (btrfs_find_device(fs_info->fs_devices,
+-                                    BTRFS_DEV_REPLACE_DEVID, NULL, NULL)) {
++              if (btrfs_find_device(fs_info->fs_devices, &args)) {
+                       btrfs_err(fs_info,
+                       "found replace target device without a valid replace item");
+                       ret = -EUCLEAN;
+@@ -163,8 +163,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
+                * We don't have an active replace item but if there is a
+                * replace target, fail the mount.
+                */
+-              if (btrfs_find_device(fs_info->fs_devices,
+-                                    BTRFS_DEV_REPLACE_DEVID, NULL, NULL)) {
++              if (btrfs_find_device(fs_info->fs_devices, &args)) {
+                       btrfs_err(fs_info,
+                       "replace devid present without an active replace item");
+                       ret = -EUCLEAN;
+@@ -175,11 +174,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+-              dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices,
+-                                              src_devid, NULL, NULL);
+-              dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices,
+-                                                      BTRFS_DEV_REPLACE_DEVID,
+-                                                      NULL, NULL);
++              dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices, &args);
++              args.devid = src_devid;
++              dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices, &args);
++
+               /*
+                * allow 'btrfs dev replace_cancel' if src/tgt device is
+                * missing
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index a37ab3e89a3b..4951a2ab88dd 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -1657,6 +1657,7 @@ static int exclop_start_or_cancel_reloc(struct btrfs_fs_info *fs_info,
+ static noinline int btrfs_ioctl_resize(struct file *file,
+                                       void __user *arg)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct inode *inode = file_inode(file);
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       u64 new_size;
+@@ -1712,7 +1713,8 @@ static noinline int btrfs_ioctl_resize(struct file *file,
+               btrfs_info(fs_info, "resizing devid %llu", devid);
+       }
+-      device = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++      args.devid = devid;
++      device = btrfs_find_device(fs_info->fs_devices, &args);
+       if (!device) {
+               btrfs_info(fs_info, "resizer unable to find device %llu",
+                          devid);
+@@ -3375,22 +3377,21 @@ static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info,
+ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,
+                                void __user *arg)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_ioctl_dev_info_args *di_args;
+       struct btrfs_device *dev;
+       int ret = 0;
+-      char *s_uuid = NULL;
+       di_args = memdup_user(arg, sizeof(*di_args));
+       if (IS_ERR(di_args))
+               return PTR_ERR(di_args);
++      args.devid = di_args->devid;
+       if (!btrfs_is_empty_uuid(di_args->uuid))
+-              s_uuid = di_args->uuid;
++              args.uuid = di_args->uuid;
+       rcu_read_lock();
+-      dev = btrfs_find_device(fs_info->fs_devices, di_args->devid, s_uuid,
+-                              NULL);
+-
++      dev = btrfs_find_device(fs_info->fs_devices, &args);
+       if (!dev) {
+               ret = -ENODEV;
+               goto out;
+diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
+index 62f4bafbe54b..6f2787b21530 100644
+--- a/fs/btrfs/scrub.c
++++ b/fs/btrfs/scrub.c
+@@ -4068,6 +4068,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+                   u64 end, struct btrfs_scrub_progress *progress,
+                   int readonly, int is_dev_replace)
+ {
++      struct btrfs_dev_lookup_args args = { .devid = devid };
+       struct scrub_ctx *sctx;
+       int ret;
+       struct btrfs_device *dev;
+@@ -4115,7 +4116,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+               goto out_free_ctx;
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+-      dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++      dev = btrfs_find_device(fs_info->fs_devices, &args);
+       if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) &&
+                    !is_dev_replace)) {
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+@@ -4288,11 +4289,12 @@ int btrfs_scrub_cancel_dev(struct btrfs_device *dev)
+ int btrfs_scrub_progress(struct btrfs_fs_info *fs_info, u64 devid,
+                        struct btrfs_scrub_progress *progress)
+ {
++      struct btrfs_dev_lookup_args args = { .devid = devid };
+       struct btrfs_device *dev;
+       struct scrub_ctx *sctx = NULL;
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+-      dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++      dev = btrfs_find_device(fs_info->fs_devices, &args);
+       if (dev)
+               sctx = dev->scrub_ctx;
+       if (sctx)
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index fa68efd7e610..53417a1c5402 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -844,9 +844,13 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+               device = NULL;
+       } else {
++              struct btrfs_dev_lookup_args args = {
++                      .devid = devid,
++                      .uuid = disk_super->dev_item.uuid,
++              };
++
+               mutex_lock(&fs_devices->device_list_mutex);
+-              device = btrfs_find_device(fs_devices, devid,
+-                              disk_super->dev_item.uuid, NULL);
++              device = btrfs_find_device(fs_devices, &args);
+               /*
+                * If this disk has been pulled into an fs devices created by
+@@ -2360,10 +2364,9 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
+ static struct btrfs_device *btrfs_find_device_by_path(
+               struct btrfs_fs_info *fs_info, const char *device_path)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       int ret = 0;
+       struct btrfs_super_block *disk_super;
+-      u64 devid;
+-      u8 *dev_uuid;
+       struct block_device *bdev;
+       struct btrfs_device *device;
+@@ -2372,14 +2375,14 @@ static struct btrfs_device *btrfs_find_device_by_path(
+       if (ret)
+               return ERR_PTR(ret);
+-      devid = btrfs_stack_device_id(&disk_super->dev_item);
+-      dev_uuid = disk_super->dev_item.uuid;
++      args.devid = btrfs_stack_device_id(&disk_super->dev_item);
++      args.uuid = disk_super->dev_item.uuid;
+       if (btrfs_fs_incompat(fs_info, METADATA_UUID))
+-              device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+-                                         disk_super->metadata_uuid);
++              args.fsid = disk_super->metadata_uuid;
+       else
+-              device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+-                                         disk_super->fsid);
++              args.fsid = disk_super->fsid;
++
++      device = btrfs_find_device(fs_info->fs_devices, &args);
+       btrfs_release_disk_super(disk_super);
+       if (!device)
+@@ -2395,11 +2398,12 @@ struct btrfs_device *btrfs_find_device_by_devspec(
+               struct btrfs_fs_info *fs_info, u64 devid,
+               const char *device_path)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_device *device;
+       if (devid) {
+-              device = btrfs_find_device(fs_info->fs_devices, devid, NULL,
+-                                         NULL);
++              args.devid = devid;
++              device = btrfs_find_device(fs_info->fs_devices, &args);
+               if (!device)
+                       return ERR_PTR(-ENOENT);
+               return device;
+@@ -2409,14 +2413,11 @@ struct btrfs_device *btrfs_find_device_by_devspec(
+               return ERR_PTR(-EINVAL);
+       if (strcmp(device_path, "missing") == 0) {
+-              /* Find first missing device */
+-              list_for_each_entry(device, &fs_info->fs_devices->devices,
+-                                  dev_list) {
+-                      if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA,
+-                                   &device->dev_state) && !device->bdev)
+-                              return device;
+-              }
+-              return ERR_PTR(-ENOENT);
++              args.missing = true;
++              device = btrfs_find_device(fs_info->fs_devices, &args);
++              if (!device)
++                      return ERR_PTR(-ENOENT);
++              return device;
+       }
+       return btrfs_find_device_by_path(fs_info, device_path);
+@@ -2496,6 +2497,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
+  */
+ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_root *root = fs_info->chunk_root;
+       struct btrfs_path *path;
+@@ -2505,7 +2507,6 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+       struct btrfs_key key;
+       u8 fs_uuid[BTRFS_FSID_SIZE];
+       u8 dev_uuid[BTRFS_UUID_SIZE];
+-      u64 devid;
+       int ret;
+       path = btrfs_alloc_path();
+@@ -2544,13 +2545,14 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+               dev_item = btrfs_item_ptr(leaf, path->slots[0],
+                                         struct btrfs_dev_item);
+-              devid = btrfs_device_id(leaf, dev_item);
++              args.devid = btrfs_device_id(leaf, dev_item);
+               read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
+                                  BTRFS_UUID_SIZE);
+               read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
+                                  BTRFS_FSID_SIZE);
+-              device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+-                                         fs_uuid);
++              args.uuid = dev_uuid;
++              args.fsid = fs_uuid;
++              device = btrfs_find_device(fs_info->fs_devices, &args);
+               BUG_ON(!device); /* Logic error */
+               if (device->fs_devices->seeding) {
+@@ -6805,6 +6807,33 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+       return BLK_STS_OK;
+ }
++static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args,
++                                    const struct btrfs_fs_devices *fs_devices)
++{
++      if (args->fsid == NULL)
++              return true;
++      if (memcmp(fs_devices->metadata_uuid, args->fsid, BTRFS_FSID_SIZE) == 0)
++              return true;
++      return false;
++}
++
++static bool dev_args_match_device(const struct btrfs_dev_lookup_args *args,
++                                const struct btrfs_device *device)
++{
++      ASSERT((args->devid != (u64)-1) || args->missing);
++
++      if ((args->devid != (u64)-1) && device->devid != args->devid)
++              return false;
++      if (args->uuid && memcmp(device->uuid, args->uuid, BTRFS_UUID_SIZE) != 0)
++              return false;
++      if (!args->missing)
++              return true;
++      if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state) &&
++          !device->bdev)
++              return true;
++      return false;
++}
++
+ /*
+  * Find a device specified by @devid or @uuid in the list of @fs_devices, or
+  * return NULL.
+@@ -6812,31 +6841,25 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+  * If devid and uuid are both specified, the match must be exact, otherwise
+  * only devid is used.
+  */
+-struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
+-                                     u64 devid, u8 *uuid, u8 *fsid)
++struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices,
++                                     const struct btrfs_dev_lookup_args *args)
+ {
+       struct btrfs_device *device;
+       struct btrfs_fs_devices *seed_devs;
+-      if (!fsid || !memcmp(fs_devices->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
++      if (dev_args_match_fs_devices(args, fs_devices)) {
+               list_for_each_entry(device, &fs_devices->devices, dev_list) {
+-                      if (device->devid == devid &&
+-                          (!uuid || memcmp(device->uuid, uuid,
+-                                           BTRFS_UUID_SIZE) == 0))
++                      if (dev_args_match_device(args, device))
+                               return device;
+               }
+       }
+       list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
+-              if (!fsid ||
+-                  !memcmp(seed_devs->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
+-                      list_for_each_entry(device, &seed_devs->devices,
+-                                          dev_list) {
+-                              if (device->devid == devid &&
+-                                  (!uuid || memcmp(device->uuid, uuid,
+-                                                   BTRFS_UUID_SIZE) == 0))
+-                                      return device;
+-                      }
++              if (!dev_args_match_fs_devices(args, seed_devs))
++                      continue;
++              list_for_each_entry(device, &seed_devs->devices, dev_list) {
++                      if (dev_args_match_device(args, device))
++                              return device;
+               }
+       }
+@@ -7002,6 +7025,7 @@ static void warn_32bit_meta_chunk(struct btrfs_fs_info *fs_info,
+ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
+                         struct btrfs_chunk *chunk)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_fs_info *fs_info = leaf->fs_info;
+       struct extent_map_tree *map_tree = &fs_info->mapping_tree;
+       struct map_lookup *map;
+@@ -7079,11 +7103,12 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
+               map->stripes[i].physical =
+                       btrfs_stripe_offset_nr(leaf, chunk, i);
+               devid = btrfs_stripe_devid_nr(leaf, chunk, i);
++              args.devid = devid;
+               read_extent_buffer(leaf, uuid, (unsigned long)
+                                  btrfs_stripe_dev_uuid_nr(chunk, i),
+                                  BTRFS_UUID_SIZE);
+-              map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices,
+-                                                      devid, uuid, NULL);
++              args.uuid = uuid;
++              map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices, &args);
+               if (!map->stripes[i].dev &&
+                   !btrfs_test_opt(fs_info, DEGRADED)) {
+                       free_extent_map(em);
+@@ -7201,6 +7226,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
+ static int read_one_dev(struct extent_buffer *leaf,
+                       struct btrfs_dev_item *dev_item)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_fs_info *fs_info = leaf->fs_info;
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+       struct btrfs_device *device;
+@@ -7209,11 +7235,13 @@ static int read_one_dev(struct extent_buffer *leaf,
+       u8 fs_uuid[BTRFS_FSID_SIZE];
+       u8 dev_uuid[BTRFS_UUID_SIZE];
+-      devid = btrfs_device_id(leaf, dev_item);
++      devid = args.devid = btrfs_device_id(leaf, dev_item);
+       read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
+                          BTRFS_UUID_SIZE);
+       read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
+                          BTRFS_FSID_SIZE);
++      args.uuid = dev_uuid;
++      args.fsid = fs_uuid;
+       if (memcmp(fs_uuid, fs_devices->metadata_uuid, BTRFS_FSID_SIZE)) {
+               fs_devices = open_seed_devices(fs_info, fs_uuid);
+@@ -7221,8 +7249,7 @@ static int read_one_dev(struct extent_buffer *leaf,
+                       return PTR_ERR(fs_devices);
+       }
+-      device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+-                                 fs_uuid);
++      device = btrfs_find_device(fs_info->fs_devices, &args);
+       if (!device) {
+               if (!btrfs_test_opt(fs_info, DEGRADED)) {
+                       btrfs_report_missing_device(fs_info, devid,
+@@ -7899,12 +7926,14 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
+ int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info,
+                       struct btrfs_ioctl_get_dev_stats *stats)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct btrfs_device *dev;
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+       int i;
+       mutex_lock(&fs_devices->device_list_mutex);
+-      dev = btrfs_find_device(fs_info->fs_devices, stats->devid, NULL, NULL);
++      args.devid = stats->devid;
++      dev = btrfs_find_device(fs_info->fs_devices, &args);
+       mutex_unlock(&fs_devices->device_list_mutex);
+       if (!dev) {
+@@ -7980,6 +8009,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
+                                u64 chunk_offset, u64 devid,
+                                u64 physical_offset, u64 physical_len)
+ {
++      struct btrfs_dev_lookup_args args = { .devid = devid };
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree;
+       struct extent_map *em;
+       struct map_lookup *map;
+@@ -8035,7 +8065,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
+       }
+       /* Make sure no dev extent is beyond device boundary */
+-      dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++      dev = btrfs_find_device(fs_info->fs_devices, &args);
+       if (!dev) {
+               btrfs_err(fs_info, "failed to find devid %llu", devid);
+               ret = -EUCLEAN;
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index d86a6f9f166c..f3b1380f45ad 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -418,6 +418,22 @@ struct btrfs_balance_control {
+       struct btrfs_balance_progress stat;
+ };
++/*
++ * Search for a given device by the set parameters
++ */
++struct btrfs_dev_lookup_args {
++      u64 devid;
++      u8 *uuid;
++      u8 *fsid;
++      bool missing;
++};
++
++/* We have to initialize to -1 because BTRFS_DEV_REPLACE_DEVID is 0 */
++#define BTRFS_DEV_LOOKUP_ARGS_INIT { .devid = (u64)-1 }
++
++#define BTRFS_DEV_LOOKUP_ARGS(name) \
++      struct btrfs_dev_lookup_args name = BTRFS_DEV_LOOKUP_ARGS_INIT
++
+ enum btrfs_map_op {
+       BTRFS_MAP_READ,
+       BTRFS_MAP_WRITE,
+@@ -482,8 +498,8 @@ void __exit btrfs_cleanup_fs_uuids(void);
+ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
+ int btrfs_grow_device(struct btrfs_trans_handle *trans,
+                     struct btrfs_device *device, u64 new_size);
+-struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
+-                                     u64 devid, u8 *uuid, u8 *fsid);
++struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices,
++                                     const struct btrfs_dev_lookup_args *args);
+ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
+ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *path);
+ int btrfs_balance(struct btrfs_fs_info *fs_info,
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-remove-device-item-and-update-super-block-in-t.patch b/queue-5.15/btrfs-remove-device-item-and-update-super-block-in-t.patch
new file mode 100644 (file)
index 0000000..da1cd0f
--- /dev/null
@@ -0,0 +1,222 @@
+From f9299e270e8f21fbf7fc1ba5e0c240cebb10825c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Mar 2022 13:36:38 +0800
+Subject: btrfs: remove device item and update super block in the same
+ transaction
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit bbac58698a55cc0a6f0c0d69a6dcd3f9f3134c11 ]
+
+[BUG]
+There is a report that a btrfs has a bad super block num devices.
+
+This makes btrfs to reject the fs completely.
+
+  BTRFS error (device sdd3): super_num_devices 3 mismatch with num_devices 2 found here
+  BTRFS error (device sdd3): failed to read chunk tree: -22
+  BTRFS error (device sdd3): open_ctree failed
+
+[CAUSE]
+During btrfs device removal, chunk tree and super block num devs are
+updated in two different transactions:
+
+  btrfs_rm_device()
+  |- btrfs_rm_dev_item(device)
+  |  |- trans = btrfs_start_transaction()
+  |  |  Now we got transaction X
+  |  |
+  |  |- btrfs_del_item()
+  |  |  Now device item is removed from chunk tree
+  |  |
+  |  |- btrfs_commit_transaction()
+  |     Transaction X got committed, super num devs untouched,
+  |     but device item removed from chunk tree.
+  |     (AKA, super num devs is already incorrect)
+  |
+  |- cur_devices->num_devices--;
+  |- cur_devices->total_devices--;
+  |- btrfs_set_super_num_devices()
+     All those operations are not in transaction X, thus it will
+     only be written back to disk in next transaction.
+
+So after the transaction X in btrfs_rm_dev_item() committed, but before
+transaction X+1 (which can be minutes away), a power loss happen, then
+we got the super num mismatch.
+
+[FIX]
+Instead of starting and committing a transaction inside
+btrfs_rm_dev_item(), start a transaction in side btrfs_rm_device() and
+pass it to btrfs_rm_dev_item().
+
+And only commit the transaction after everything is done.
+
+Reported-by: Luca Béla Palkovics <luca.bela.palkovics@gmail.com>
+Link: https://lore.kernel.org/linux-btrfs/CA+8xDSpvdm_U0QLBAnrH=zqDq_cWCOH5TiV46CKmp3igr44okQ@mail.gmail.com/
+CC: stable@vger.kernel.org # 4.14+
+Reviewed-by: Anand Jain <anand.jain@oracle.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/volumes.c | 65 ++++++++++++++++++++--------------------------
+ 1 file changed, 28 insertions(+), 37 deletions(-)
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 3bd68f1b79e6..cec54c6e1cdd 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1942,23 +1942,18 @@ static void update_dev_time(const char *device_path)
+       path_put(&path);
+ }
+-static int btrfs_rm_dev_item(struct btrfs_device *device)
++static int btrfs_rm_dev_item(struct btrfs_trans_handle *trans,
++                           struct btrfs_device *device)
+ {
+       struct btrfs_root *root = device->fs_info->chunk_root;
+       int ret;
+       struct btrfs_path *path;
+       struct btrfs_key key;
+-      struct btrfs_trans_handle *trans;
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+-      trans = btrfs_start_transaction(root, 0);
+-      if (IS_ERR(trans)) {
+-              btrfs_free_path(path);
+-              return PTR_ERR(trans);
+-      }
+       key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
+       key.type = BTRFS_DEV_ITEM_KEY;
+       key.offset = device->devid;
+@@ -1969,21 +1964,12 @@ static int btrfs_rm_dev_item(struct btrfs_device *device)
+       if (ret) {
+               if (ret > 0)
+                       ret = -ENOENT;
+-              btrfs_abort_transaction(trans, ret);
+-              btrfs_end_transaction(trans);
+               goto out;
+       }
+       ret = btrfs_del_item(trans, root, path);
+-      if (ret) {
+-              btrfs_abort_transaction(trans, ret);
+-              btrfs_end_transaction(trans);
+-      }
+-
+ out:
+       btrfs_free_path(path);
+-      if (!ret)
+-              ret = btrfs_commit_transaction(trans);
+       return ret;
+ }
+@@ -2124,6 +2110,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+                   struct btrfs_dev_lookup_args *args,
+                   struct block_device **bdev, fmode_t *mode)
+ {
++      struct btrfs_trans_handle *trans;
+       struct btrfs_device *device;
+       struct btrfs_fs_devices *cur_devices;
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+@@ -2139,7 +2126,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+       ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1);
+       if (ret)
+-              goto out;
++              return ret;
+       device = btrfs_find_device(fs_info->fs_devices, args);
+       if (!device) {
+@@ -2147,27 +2134,22 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+                       ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND;
+               else
+                       ret = -ENOENT;
+-              goto out;
++              return ret;
+       }
+       if (btrfs_pinned_by_swapfile(fs_info, device)) {
+               btrfs_warn_in_rcu(fs_info,
+                 "cannot remove device %s (devid %llu) due to active swapfile",
+                                 rcu_str_deref(device->name), device->devid);
+-              ret = -ETXTBSY;
+-              goto out;
++              return -ETXTBSY;
+       }
+-      if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
+-              ret = BTRFS_ERROR_DEV_TGT_REPLACE;
+-              goto out;
+-      }
++      if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state))
++              return BTRFS_ERROR_DEV_TGT_REPLACE;
+       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
+-          fs_info->fs_devices->rw_devices == 1) {
+-              ret = BTRFS_ERROR_DEV_ONLY_WRITABLE;
+-              goto out;
+-      }
++          fs_info->fs_devices->rw_devices == 1)
++              return BTRFS_ERROR_DEV_ONLY_WRITABLE;
+       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
+               mutex_lock(&fs_info->chunk_mutex);
+@@ -2182,14 +2164,22 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+       if (ret)
+               goto error_undo;
+-      /*
+-       * TODO: the superblock still includes this device in its num_devices
+-       * counter although write_all_supers() is not locked out. This
+-       * could give a filesystem state which requires a degraded mount.
+-       */
+-      ret = btrfs_rm_dev_item(device);
+-      if (ret)
++      trans = btrfs_start_transaction(fs_info->chunk_root, 0);
++      if (IS_ERR(trans)) {
++              ret = PTR_ERR(trans);
+               goto error_undo;
++      }
++
++      ret = btrfs_rm_dev_item(trans, device);
++      if (ret) {
++              /* Any error in dev item removal is critical */
++              btrfs_crit(fs_info,
++                         "failed to remove device item for devid %llu: %d",
++                         device->devid, ret);
++              btrfs_abort_transaction(trans, ret);
++              btrfs_end_transaction(trans);
++              return ret;
++      }
+       clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
+       btrfs_scrub_cancel_dev(device);
+@@ -2264,7 +2254,8 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+               free_fs_devices(cur_devices);
+       }
+-out:
++      ret = btrfs_commit_transaction(trans);
++
+       return ret;
+ error_undo:
+@@ -2276,7 +2267,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+               device->fs_devices->rw_devices++;
+               mutex_unlock(&fs_info->chunk_mutex);
+       }
+-      goto out;
++      return ret;
+ }
+ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev)
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch b/queue-5.15/btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch
new file mode 100644 (file)
index 0000000..0d538d4
--- /dev/null
@@ -0,0 +1,142 @@
+From 60929c7175f80f919e5d93bcaea7a3a23650a1b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Aug 2021 13:41:19 +0300
+Subject: btrfs: rename btrfs_alloc_chunk to btrfs_create_chunk
+
+From: Nikolay Borisov <nborisov@suse.com>
+
+[ Upstream commit f6f39f7a0add4e7fd120a709545b57586a1d0393 ]
+
+The user facing function used to allocate new chunks is
+btrfs_chunk_alloc, unfortunately there is yet another similar sounding
+function - btrfs_alloc_chunk. This creates confusion, especially since
+the latter function can be considered "private" in the sense that it
+implements the first stage of chunk creation and as such is called by
+btrfs_chunk_alloc.
+
+To avoid the awkwardness that comes with having similarly named but
+distinctly different in their purpose function rename btrfs_alloc_chunk
+to btrfs_create_chunk, given that the main purpose of this function is
+to orchestrate the whole process of allocating a chunk - reserving space
+into devices, deciding on characteristics of the stripe size and
+creating the in-memory structures.
+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: Anand Jain <anand.jain@oracle.com>
+Signed-off-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/block-group.c |  6 +++---
+ fs/btrfs/volumes.c     | 10 +++++-----
+ fs/btrfs/volumes.h     |  2 +-
+ fs/btrfs/zoned.c       |  2 +-
+ 4 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
+index 37418b183b07..aadc1203ad88 100644
+--- a/fs/btrfs/block-group.c
++++ b/fs/btrfs/block-group.c
+@@ -3400,7 +3400,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
+        */
+       check_system_chunk(trans, flags);
+-      bg = btrfs_alloc_chunk(trans, flags);
++      bg = btrfs_create_chunk(trans, flags);
+       if (IS_ERR(bg)) {
+               ret = PTR_ERR(bg);
+               goto out;
+@@ -3461,7 +3461,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
+               const u64 sys_flags = btrfs_system_alloc_profile(trans->fs_info);
+               struct btrfs_block_group *sys_bg;
+-              sys_bg = btrfs_alloc_chunk(trans, sys_flags);
++              sys_bg = btrfs_create_chunk(trans, sys_flags);
+               if (IS_ERR(sys_bg)) {
+                       ret = PTR_ERR(sys_bg);
+                       btrfs_abort_transaction(trans, ret);
+@@ -3754,7 +3754,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+                * could deadlock on an extent buffer since our caller may be
+                * COWing an extent buffer from the chunk btree.
+                */
+-              bg = btrfs_alloc_chunk(trans, flags);
++              bg = btrfs_create_chunk(trans, flags);
+               if (IS_ERR(bg)) {
+                       ret = PTR_ERR(bg);
+               } else if (!(type & BTRFS_BLOCK_GROUP_SYSTEM)) {
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 378e03a93e10..b75ce79a2540 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -3131,7 +3131,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
+               const u64 sys_flags = btrfs_system_alloc_profile(fs_info);
+               struct btrfs_block_group *sys_bg;
+-              sys_bg = btrfs_alloc_chunk(trans, sys_flags);
++              sys_bg = btrfs_create_chunk(trans, sys_flags);
+               if (IS_ERR(sys_bg)) {
+                       ret = PTR_ERR(sys_bg);
+                       btrfs_abort_transaction(trans, ret);
+@@ -5010,7 +5010,7 @@ static void check_raid1c34_incompat_flag(struct btrfs_fs_info *info, u64 type)
+ }
+ /*
+- * Structure used internally for __btrfs_alloc_chunk() function.
++ * Structure used internally for btrfs_create_chunk() function.
+  * Wraps needed parameters.
+  */
+ struct alloc_chunk_ctl {
+@@ -5414,7 +5414,7 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans,
+       return block_group;
+ }
+-struct btrfs_block_group *btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
++struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
+                                           u64 type)
+ {
+       struct btrfs_fs_info *info = trans->fs_info;
+@@ -5615,12 +5615,12 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans)
+        */
+       alloc_profile = btrfs_metadata_alloc_profile(fs_info);
+-      meta_bg = btrfs_alloc_chunk(trans, alloc_profile);
++      meta_bg = btrfs_create_chunk(trans, alloc_profile);
+       if (IS_ERR(meta_bg))
+               return PTR_ERR(meta_bg);
+       alloc_profile = btrfs_system_alloc_profile(fs_info);
+-      sys_bg = btrfs_alloc_chunk(trans, alloc_profile);
++      sys_bg = btrfs_create_chunk(trans, alloc_profile);
+       if (IS_ERR(sys_bg))
+               return PTR_ERR(sys_bg);
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index 4db10d071d67..d86a6f9f166c 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -454,7 +454,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *map,
+                         struct btrfs_io_geometry *io_geom);
+ int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
+ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
+-struct btrfs_block_group *btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
++struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
+                                           u64 type);
+ void btrfs_mapping_tree_free(struct extent_map_tree *tree);
+ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 596b2148807d..3bc2f92cd197 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -636,7 +636,7 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
+       /*
+        * stripe_size is always aligned to BTRFS_STRIPE_LEN in
+-       * __btrfs_alloc_chunk(). Since we want stripe_len == zone_size,
++       * btrfs_create_chunk(). Since we want stripe_len == zone_size,
+        * check the alignment here.
+        */
+       if (!IS_ALIGNED(zone_size, BTRFS_STRIPE_LEN)) {
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch b/queue-5.15/btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch
new file mode 100644 (file)
index 0000000..1b784f3
--- /dev/null
@@ -0,0 +1,331 @@
+From 67dd3976212537f741bf75ed1efd707ea2ec78d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Oct 2021 16:12:44 -0400
+Subject: btrfs: use btrfs_get_dev_args_from_path in dev removal ioctls
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+[ Upstream commit 1a15eb724aaef8656f8cc01d9355797cfe7c618e ]
+
+For device removal and replace we call btrfs_find_device_by_devspec,
+which if we give it a device path and nothing else will call
+btrfs_get_dev_args_from_path, which opens the block device and reads the
+super block and then looks up our device based on that.
+
+However at this point we're holding the sb write "lock", so reading the
+block device pulls in the dependency of ->open_mutex, which produces the
+following lockdep splat
+
+======================================================
+WARNING: possible circular locking dependency detected
+5.14.0-rc2+ #405 Not tainted
+------------------------------------------------------
+losetup/11576 is trying to acquire lock:
+ffff9bbe8cded938 ((wq_completion)loop0){+.+.}-{0:0}, at: flush_workqueue+0x67/0x5e0
+
+but task is already holding lock:
+ffff9bbe88e4fc68 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x41/0x660 [loop]
+
+which lock already depends on the new lock.
+
+the existing dependency chain (in reverse order) is:
+
+-> #4 (&lo->lo_mutex){+.+.}-{3:3}:
+       __mutex_lock+0x7d/0x750
+       lo_open+0x28/0x60 [loop]
+       blkdev_get_whole+0x25/0xf0
+       blkdev_get_by_dev.part.0+0x168/0x3c0
+       blkdev_open+0xd2/0xe0
+       do_dentry_open+0x161/0x390
+       path_openat+0x3cc/0xa20
+       do_filp_open+0x96/0x120
+       do_sys_openat2+0x7b/0x130
+       __x64_sys_openat+0x46/0x70
+       do_syscall_64+0x38/0x90
+       entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+-> #3 (&disk->open_mutex){+.+.}-{3:3}:
+       __mutex_lock+0x7d/0x750
+       blkdev_get_by_dev.part.0+0x56/0x3c0
+       blkdev_get_by_path+0x98/0xa0
+       btrfs_get_bdev_and_sb+0x1b/0xb0
+       btrfs_find_device_by_devspec+0x12b/0x1c0
+       btrfs_rm_device+0x127/0x610
+       btrfs_ioctl+0x2a31/0x2e70
+       __x64_sys_ioctl+0x80/0xb0
+       do_syscall_64+0x38/0x90
+       entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+-> #2 (sb_writers#12){.+.+}-{0:0}:
+       lo_write_bvec+0xc2/0x240 [loop]
+       loop_process_work+0x238/0xd00 [loop]
+       process_one_work+0x26b/0x560
+       worker_thread+0x55/0x3c0
+       kthread+0x140/0x160
+       ret_from_fork+0x1f/0x30
+
+-> #1 ((work_completion)(&lo->rootcg_work)){+.+.}-{0:0}:
+       process_one_work+0x245/0x560
+       worker_thread+0x55/0x3c0
+       kthread+0x140/0x160
+       ret_from_fork+0x1f/0x30
+
+-> #0 ((wq_completion)loop0){+.+.}-{0:0}:
+       __lock_acquire+0x10ea/0x1d90
+       lock_acquire+0xb5/0x2b0
+       flush_workqueue+0x91/0x5e0
+       drain_workqueue+0xa0/0x110
+       destroy_workqueue+0x36/0x250
+       __loop_clr_fd+0x9a/0x660 [loop]
+       block_ioctl+0x3f/0x50
+       __x64_sys_ioctl+0x80/0xb0
+       do_syscall_64+0x38/0x90
+       entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+other info that might help us debug this:
+
+Chain exists of:
+  (wq_completion)loop0 --> &disk->open_mutex --> &lo->lo_mutex
+
+ Possible unsafe locking scenario:
+
+       CPU0                    CPU1
+       ----                    ----
+  lock(&lo->lo_mutex);
+                               lock(&disk->open_mutex);
+                               lock(&lo->lo_mutex);
+  lock((wq_completion)loop0);
+
+ *** DEADLOCK ***
+
+1 lock held by losetup/11576:
+ #0: ffff9bbe88e4fc68 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x41/0x660 [loop]
+
+stack backtrace:
+CPU: 0 PID: 11576 Comm: losetup Not tainted 5.14.0-rc2+ #405
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-2.fc32 04/01/2014
+Call Trace:
+ dump_stack_lvl+0x57/0x72
+ check_noncircular+0xcf/0xf0
+ ? stack_trace_save+0x3b/0x50
+ __lock_acquire+0x10ea/0x1d90
+ lock_acquire+0xb5/0x2b0
+ ? flush_workqueue+0x67/0x5e0
+ ? lockdep_init_map_type+0x47/0x220
+ flush_workqueue+0x91/0x5e0
+ ? flush_workqueue+0x67/0x5e0
+ ? verify_cpu+0xf0/0x100
+ drain_workqueue+0xa0/0x110
+ destroy_workqueue+0x36/0x250
+ __loop_clr_fd+0x9a/0x660 [loop]
+ ? blkdev_ioctl+0x8d/0x2a0
+ block_ioctl+0x3f/0x50
+ __x64_sys_ioctl+0x80/0xb0
+ do_syscall_64+0x38/0x90
+ entry_SYSCALL_64_after_hwframe+0x44/0xae
+RIP: 0033:0x7f31b02404cb
+
+Instead what we want to do is populate our device lookup args before we
+grab any locks, and then pass these args into btrfs_rm_device().  From
+there we can find the device and do the appropriate removal.
+
+Suggested-by: Anand Jain <anand.jain@oracle.com>
+Reviewed-by: Anand Jain <anand.jain@oracle.com>
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ioctl.c   | 67 +++++++++++++++++++++++++++-------------------
+ fs/btrfs/volumes.c | 15 +++++------
+ fs/btrfs/volumes.h |  2 +-
+ 3 files changed, 48 insertions(+), 36 deletions(-)
+
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index 4951a2ab88dd..4317720a29e8 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -3218,6 +3218,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
+ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct inode *inode = file_inode(file);
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       struct btrfs_ioctl_vol_args_v2 *vol_args;
+@@ -3229,35 +3230,39 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+-      ret = mnt_want_write_file(file);
+-      if (ret)
+-              return ret;
+-
+       vol_args = memdup_user(arg, sizeof(*vol_args));
+       if (IS_ERR(vol_args)) {
+               ret = PTR_ERR(vol_args);
+-              goto err_drop;
++              goto out;
+       }
+       if (vol_args->flags & ~BTRFS_DEVICE_REMOVE_ARGS_MASK) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
++
+       vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+-      if (!(vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) &&
+-          strcmp("cancel", vol_args->name) == 0)
++      if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) {
++              args.devid = vol_args->devid;
++      } else if (!strcmp("cancel", vol_args->name)) {
+               cancel = true;
++      } else {
++              ret = btrfs_get_dev_args_from_path(fs_info, &args, vol_args->name);
++              if (ret)
++                      goto out;
++      }
++
++      ret = mnt_want_write_file(file);
++      if (ret)
++              goto out;
+       ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
+                                          cancel);
+       if (ret)
+-              goto out;
+-      /* Exclusive operation is now claimed */
++              goto err_drop;
+-      if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID)
+-              ret = btrfs_rm_device(fs_info, NULL, vol_args->devid, &bdev, &mode);
+-      else
+-              ret = btrfs_rm_device(fs_info, vol_args->name, 0, &bdev, &mode);
++      /* Exclusive operation is now claimed */
++      ret = btrfs_rm_device(fs_info, &args, &bdev, &mode);
+       btrfs_exclop_finish(fs_info);
+@@ -3269,17 +3274,19 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
+                       btrfs_info(fs_info, "device deleted: %s",
+                                       vol_args->name);
+       }
+-out:
+-      kfree(vol_args);
+ err_drop:
+       mnt_drop_write_file(file);
+       if (bdev)
+               blkdev_put(bdev, mode);
++out:
++      btrfs_put_dev_args_from_path(&args);
++      kfree(vol_args);
+       return ret;
+ }
+ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
+ {
++      BTRFS_DEV_LOOKUP_ARGS(args);
+       struct inode *inode = file_inode(file);
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       struct btrfs_ioctl_vol_args *vol_args;
+@@ -3291,32 +3298,38 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+-      ret = mnt_want_write_file(file);
+-      if (ret)
+-              return ret;
+-
+       vol_args = memdup_user(arg, sizeof(*vol_args));
+-      if (IS_ERR(vol_args)) {
+-              ret = PTR_ERR(vol_args);
+-              goto out_drop_write;
+-      }
++      if (IS_ERR(vol_args))
++              return PTR_ERR(vol_args);
++
+       vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
+-      cancel = (strcmp("cancel", vol_args->name) == 0);
++      if (!strcmp("cancel", vol_args->name)) {
++              cancel = true;
++      } else {
++              ret = btrfs_get_dev_args_from_path(fs_info, &args, vol_args->name);
++              if (ret)
++                      goto out;
++      }
++
++      ret = mnt_want_write_file(file);
++      if (ret)
++              goto out;
+       ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
+                                          cancel);
+       if (ret == 0) {
+-              ret = btrfs_rm_device(fs_info, vol_args->name, 0, &bdev, &mode);
++              ret = btrfs_rm_device(fs_info, &args, &bdev, &mode);
+               if (!ret)
+                       btrfs_info(fs_info, "disk deleted %s", vol_args->name);
+               btrfs_exclop_finish(fs_info);
+       }
+-      kfree(vol_args);
+-out_drop_write:
+       mnt_drop_write_file(file);
+       if (bdev)
+               blkdev_put(bdev, mode);
++out:
++      btrfs_put_dev_args_from_path(&args);
++      kfree(vol_args);
+       return ret;
+ }
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 8d09e6d442b2..3bd68f1b79e6 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -2120,8 +2120,9 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+       update_dev_time(device_path);
+ }
+-int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+-                  u64 devid, struct block_device **bdev, fmode_t *mode)
++int btrfs_rm_device(struct btrfs_fs_info *fs_info,
++                  struct btrfs_dev_lookup_args *args,
++                  struct block_device **bdev, fmode_t *mode)
+ {
+       struct btrfs_device *device;
+       struct btrfs_fs_devices *cur_devices;
+@@ -2140,14 +2141,12 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+       if (ret)
+               goto out;
+-      device = btrfs_find_device_by_devspec(fs_info, devid, device_path);
+-
+-      if (IS_ERR(device)) {
+-              if (PTR_ERR(device) == -ENOENT &&
+-                  device_path && strcmp(device_path, "missing") == 0)
++      device = btrfs_find_device(fs_info->fs_devices, args);
++      if (!device) {
++              if (args->missing)
+                       ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND;
+               else
+-                      ret = PTR_ERR(device);
++                      ret = -ENOENT;
+               goto out;
+       }
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index d1df03f77e29..30288b728bbb 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -496,7 +496,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
+ void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
+ void btrfs_free_device(struct btrfs_device *device);
+ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+-                  const char *device_path, u64 devid,
++                  struct btrfs_dev_lookup_args *args,
+                   struct block_device **bdev, fmode_t *mode);
+ void __exit btrfs_cleanup_fs_uuids(void);
+ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch b/queue-5.15/btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch
new file mode 100644 (file)
index 0000000..6aac13d
--- /dev/null
@@ -0,0 +1,88 @@
+From a32dd92cd015cd2acfe3895afc45c4ea73c72d2a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Dec 2021 06:28:34 -0800
+Subject: btrfs: zoned: encapsulate inode locking for zoned relocation
+
+From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+
+[ Upstream commit 869f4cdc73f9378986755030c684c011f0b71517 ]
+
+Encapsulate the inode lock needed for serializing the data relocation
+writes on a zoned filesystem into a helper.
+
+This streamlines the code reading flow and hides special casing for
+zoned filesystems.
+
+Reviewed-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_io.c |  8 ++------
+ fs/btrfs/zoned.h     | 17 +++++++++++++++++
+ 2 files changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index 6dd375ed6e3d..059bd0753e27 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -5139,8 +5139,6 @@ int extent_writepages(struct address_space *mapping,
+                     struct writeback_control *wbc)
+ {
+       struct inode *inode = mapping->host;
+-      const bool data_reloc = btrfs_is_data_reloc_root(BTRFS_I(inode)->root);
+-      const bool zoned = btrfs_is_zoned(BTRFS_I(inode)->root->fs_info);
+       int ret = 0;
+       struct extent_page_data epd = {
+               .bio_ctrl = { 0 },
+@@ -5152,11 +5150,9 @@ int extent_writepages(struct address_space *mapping,
+        * Allow only a single thread to do the reloc work in zoned mode to
+        * protect the write pointer updates.
+        */
+-      if (data_reloc && zoned)
+-              btrfs_inode_lock(inode, 0);
++      btrfs_zoned_data_reloc_lock(BTRFS_I(inode));
+       ret = extent_write_cache_pages(mapping, wbc, &epd);
+-      if (data_reloc && zoned)
+-              btrfs_inode_unlock(inode, 0);
++      btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
+       ASSERT(ret <= 0);
+       if (ret < 0) {
+               end_write_bio(&epd, ret);
+diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
+index 813aa3cddc11..d680c3ee918a 100644
+--- a/fs/btrfs/zoned.h
++++ b/fs/btrfs/zoned.h
+@@ -8,6 +8,7 @@
+ #include "volumes.h"
+ #include "disk-io.h"
+ #include "block-group.h"
++#include "btrfs_inode.h"
+ /*
+  * Block groups with more than this value (percents) of unusable space will be
+@@ -324,4 +325,20 @@ static inline void btrfs_clear_treelog_bg(struct btrfs_block_group *bg)
+       spin_unlock(&fs_info->treelog_bg_lock);
+ }
++static inline void btrfs_zoned_data_reloc_lock(struct btrfs_inode *inode)
++{
++      struct btrfs_root *root = inode->root;
++
++      if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info))
++              btrfs_inode_lock(&inode->vfs_inode, 0);
++}
++
++static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode)
++{
++      struct btrfs_root *root = inode->root;
++
++      if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info))
++              btrfs_inode_unlock(&inode->vfs_inode, 0);
++}
++
+ #endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/btrfs-zoned-use-dedicated-lock-for-data-relocation.patch b/queue-5.15/btrfs-zoned-use-dedicated-lock-for-data-relocation.patch
new file mode 100644 (file)
index 0000000..f2adc79
--- /dev/null
@@ -0,0 +1,107 @@
+From 69391698b4b697b1167e7438b0e53ed3f61f460d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 18 Apr 2022 16:15:03 +0900
+Subject: btrfs: zoned: use dedicated lock for data relocation
+
+From: Naohiro Aota <naohiro.aota@wdc.com>
+
+[ Upstream commit 5f0addf7b89085f8e0a2593faa419d6111612b9b ]
+
+Currently, we use btrfs_inode_{lock,unlock}() to grant an exclusive
+writeback of the relocation data inode in
+btrfs_zoned_data_reloc_{lock,unlock}(). However, that can cause a deadlock
+in the following path.
+
+Thread A takes btrfs_inode_lock() and waits for metadata reservation by
+e.g, waiting for writeback:
+
+prealloc_file_extent_cluster()
+  - btrfs_inode_lock(&inode->vfs_inode, 0);
+  - btrfs_prealloc_file_range()
+  ...
+    - btrfs_replace_file_extents()
+      - btrfs_start_transaction
+      ...
+        - btrfs_reserve_metadata_bytes()
+
+Thread B (e.g, doing a writeback work) needs to wait for the inode lock to
+continue writeback process:
+
+do_writepages
+  - btrfs_writepages
+    - extent_writpages
+      - btrfs_zoned_data_reloc_lock(BTRFS_I(inode));
+        - btrfs_inode_lock()
+
+The deadlock is caused by relying on the vfs_inode's lock. By using it, we
+introduced unnecessary exclusion of writeback and
+btrfs_prealloc_file_range(). Also, the lock at this point is useless as we
+don't have any dirty pages in the inode yet.
+
+Introduce fs_info->zoned_data_reloc_io_lock and use it for the exclusive
+writeback.
+
+Fixes: 35156d852762 ("btrfs: zoned: only allow one process to add pages to a relocation inode")
+CC: stable@vger.kernel.org # 5.16.x: 869f4cdc73f9: btrfs: zoned: encapsulate inode locking for zoned relocation
+CC: stable@vger.kernel.org # 5.16.x
+CC: stable@vger.kernel.org # 5.17
+Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ctree.h   | 1 +
+ fs/btrfs/disk-io.c | 1 +
+ fs/btrfs/zoned.h   | 4 ++--
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
+index cc72d8981c47..d1838de0b39c 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -1027,6 +1027,7 @@ struct btrfs_fs_info {
+        */
+       spinlock_t relocation_bg_lock;
+       u64 data_reloc_bg;
++      struct mutex zoned_data_reloc_io_lock;
+ #ifdef CONFIG_BTRFS_FS_REF_VERIFY
+       spinlock_t ref_verify_lock;
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 233d894f6feb..909d19656316 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -2914,6 +2914,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
+       mutex_init(&fs_info->reloc_mutex);
+       mutex_init(&fs_info->delalloc_root_mutex);
+       mutex_init(&fs_info->zoned_meta_io_lock);
++      mutex_init(&fs_info->zoned_data_reloc_io_lock);
+       seqlock_init(&fs_info->profiles_lock);
+       INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
+diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
+index d680c3ee918a..3a826f7c2040 100644
+--- a/fs/btrfs/zoned.h
++++ b/fs/btrfs/zoned.h
+@@ -330,7 +330,7 @@ static inline void btrfs_zoned_data_reloc_lock(struct btrfs_inode *inode)
+       struct btrfs_root *root = inode->root;
+       if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info))
+-              btrfs_inode_lock(&inode->vfs_inode, 0);
++              mutex_lock(&root->fs_info->zoned_data_reloc_io_lock);
+ }
+ static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode)
+@@ -338,7 +338,7 @@ static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode)
+       struct btrfs_root *root = inode->root;
+       if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info))
+-              btrfs_inode_unlock(&inode->vfs_inode, 0);
++              mutex_unlock(&root->fs_info->zoned_data_reloc_io_lock);
+ }
+ #endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch b/queue-5.15/bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch
new file mode 100644 (file)
index 0000000..5ba1968
--- /dev/null
@@ -0,0 +1,67 @@
+From b919a1877dfb655cdaa1c2615ef7495b3c299833 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Dec 2021 13:42:26 +0530
+Subject: bus: mhi: core: Use correctly sized arguments for bit field
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit 5a717e93239fc373a314e03e45c43b62ebea1b26 ]
+
+The find.h APIs are designed to be used only on unsigned long arguments.
+This can technically result in a over-read, but it is harmless in this
+case. Regardless, fix it to avoid the warning seen under -Warray-bounds,
+which we'd like to enable globally:
+
+In file included from ./include/linux/bitmap.h:9,
+                 from ./include/linux/cpumask.h:12,
+                 from ./arch/x86/include/asm/cpumask.h:5,
+                 from ./arch/x86/include/asm/msr.h:11,
+                 from ./arch/x86/include/asm/processor.h:22,
+                 from ./arch/x86/include/asm/cpufeature.h:5,
+                 from ./arch/x86/include/asm/thread_info.h:53,
+                 from ./include/linux/thread_info.h:60,
+                 from ./arch/x86/include/asm/preempt.h:7,
+                 from ./include/linux/preempt.h:78,
+                 from ./include/linux/spinlock.h:55,
+                 from ./include/linux/wait.h:9,
+                 from ./include/linux/wait_bit.h:8,
+                 from ./include/linux/fs.h:6,
+                 from ./include/linux/debugfs.h:15,
+                 from drivers/bus/mhi/core/init.c:7:
+drivers/bus/mhi/core/init.c: In function 'to_mhi_pm_state_str':
+./include/linux/find.h:187:37: warning: array subscript 'long unsigned int[0]' is partly outside array bounds of 'enum mhi_pm_state[1]' [-Warray-bounds]
+  187 |                 unsigned long val = *addr & GENMASK(size - 1, 0);
+      |                                     ^~~~~
+drivers/bus/mhi/core/init.c:80:51: note: while referencing 'state'
+   80 | const char *to_mhi_pm_state_str(enum mhi_pm_state state)
+      |                                 ~~~~~~~~~~~~~~~~~~^~~~~
+
+Link: https://lore.kernel.org/r/20211215232446.2069794-1-keescook@chromium.org
+[mani: changed the variable name "bits" to "pm_state"]
+Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20211216081227.237749-10-manivannan.sadhasivam@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bus/mhi/core/init.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c
+index 4183945fc2c4..c0187367ae75 100644
+--- a/drivers/bus/mhi/core/init.c
++++ b/drivers/bus/mhi/core/init.c
+@@ -79,7 +79,8 @@ static const char * const mhi_pm_state_str[] = {
+ const char *to_mhi_pm_state_str(enum mhi_pm_state state)
+ {
+-      int index = find_last_bit((unsigned long *)&state, 32);
++      unsigned long pm_state = state;
++      int index = find_last_bit(&pm_state, 32);
+       if (index >= ARRAY_SIZE(mhi_pm_state_str))
+               return "Invalid State";
+-- 
+2.35.1
+
diff --git a/queue-5.15/bus-mhi-fix-pm_state-conversion-to-string.patch b/queue-5.15/bus-mhi-fix-pm_state-conversion-to-string.patch
new file mode 100644 (file)
index 0000000..4ef164b
--- /dev/null
@@ -0,0 +1,75 @@
+From b459a1a4993d2711f8547107174c59a767db2fc8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Mar 2022 21:33:00 +0530
+Subject: bus: mhi: Fix pm_state conversion to string
+
+From: Paul Davey <paul.davey@alliedtelesis.co.nz>
+
+[ Upstream commit 64f93a9a27c1970fa8ee5ffc5a6ae2bda477ec5b ]
+
+On big endian architectures the mhi debugfs files which report pm state
+give "Invalid State" for all states.  This is caused by using
+find_last_bit which takes an unsigned long* while the state is passed in
+as an enum mhi_pm_state which will be of int size.
+
+Fix by using __fls to pass the value of state instead of find_last_bit.
+
+Also the current API expects "mhi_pm_state" enumerator as the function
+argument but the function only works with bitmasks. So as Alex suggested,
+let's change the argument to u32 to avoid confusion.
+
+Fixes: a6e2e3522f29 ("bus: mhi: core: Add support for PM state transitions")
+Cc: stable@vger.kernel.org
+[mani: changed the function argument to u32]
+Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
+Reviewed-by: Hemant Kumar <hemantk@codeaurora.org>
+Reviewed-by: Alex Elder <elder@linaro.org>
+Signed-off-by: Paul Davey <paul.davey@alliedtelesis.co.nz>
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20220301160308.107452-3-manivannan.sadhasivam@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bus/mhi/core/init.c     | 10 ++++++----
+ drivers/bus/mhi/core/internal.h |  2 +-
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c
+index c0187367ae75..d8787aaa176b 100644
+--- a/drivers/bus/mhi/core/init.c
++++ b/drivers/bus/mhi/core/init.c
+@@ -77,12 +77,14 @@ static const char * const mhi_pm_state_str[] = {
+       [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect",
+ };
+-const char *to_mhi_pm_state_str(enum mhi_pm_state state)
++const char *to_mhi_pm_state_str(u32 state)
+ {
+-      unsigned long pm_state = state;
+-      int index = find_last_bit(&pm_state, 32);
++      int index;
+-      if (index >= ARRAY_SIZE(mhi_pm_state_str))
++      if (state)
++              index = __fls(state);
++
++      if (!state || index >= ARRAY_SIZE(mhi_pm_state_str))
+               return "Invalid State";
+       return mhi_pm_state_str[index];
+diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h
+index c02c4d48b744..71f181402be9 100644
+--- a/drivers/bus/mhi/core/internal.h
++++ b/drivers/bus/mhi/core/internal.h
+@@ -622,7 +622,7 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
+ enum mhi_pm_state __must_check mhi_tryset_pm_state(
+                                       struct mhi_controller *mhi_cntrl,
+                                       enum mhi_pm_state state);
+-const char *to_mhi_pm_state_str(enum mhi_pm_state state);
++const char *to_mhi_pm_state_str(u32 state);
+ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
+                              enum dev_st_transition state);
+ void mhi_pm_st_worker(struct work_struct *work);
+-- 
+2.35.1
+
diff --git a/queue-5.15/clk-renesas-r9a07g044-update-multiplier-and-divider-.patch b/queue-5.15/clk-renesas-r9a07g044-update-multiplier-and-divider-.patch
new file mode 100644 (file)
index 0000000..a706518
--- /dev/null
@@ -0,0 +1,45 @@
+From 8923d15e9fb7c424931d2dc97a215643e86182ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Dec 2021 09:32:23 +0000
+Subject: clk: renesas: r9a07g044: Update multiplier and divider values for
+ PLL2/3
+
+From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+[ Upstream commit b289cdecc7c3e25e001cde260c882e4d9a8b0772 ]
+
+As per the HW manual (Rev.1.00 Sep, 2021) PLL2 and PLL3 should be
+1600 MHz, but with current multiplier and divider values this resulted
+to 1596 MHz.
+
+This patch updates the multiplier and divider values for PLL2 and PLL3
+so that we get the exact (1600 MHz) values.
+
+Fixes: 17f0ff3d49ff1 ("clk: renesas: Add support for R9A07G044 SoC")
+Suggested-by: Biju Das <biju.das.jz@bp.renesas.com>
+Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20211223093223.4725-1-prabhakar.mahadev-lad.rj@bp.renesas.com
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/renesas/r9a07g044-cpg.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
+index 1490446985e2..61609eddf7d0 100644
+--- a/drivers/clk/renesas/r9a07g044-cpg.c
++++ b/drivers/clk/renesas/r9a07g044-cpg.c
+@@ -61,8 +61,8 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
+       DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
+       DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
+       DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+-      DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2),
+-      DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2),
++      DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
++      DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
+       DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+       DEF_FIXED(".pll2_div16", CLK_PLL2_DIV16, CLK_PLL2, 1, 16),
+-- 
+2.35.1
+
diff --git a/queue-5.15/compiler-attributes-add-__alloc_size-for-better-boun.patch b/queue-5.15/compiler-attributes-add-__alloc_size-for-better-boun.patch
new file mode 100644 (file)
index 0000000..fb2c8ba
--- /dev/null
@@ -0,0 +1,206 @@
+From 22cf5e03b57d30063ad34bb3e6acec618bd4f84f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Nov 2021 13:36:19 -0700
+Subject: Compiler Attributes: add __alloc_size() for better bounds checking
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit 86cffecdeaa278444870c8745ab166a65865dbf0 ]
+
+GCC and Clang can use the "alloc_size" attribute to better inform the
+results of __builtin_object_size() (for compile-time constant values).
+Clang can additionally use alloc_size to inform the results of
+__builtin_dynamic_object_size() (for run-time values).
+
+Because GCC sees the frequent use of struct_size() as an allocator size
+argument, and notices it can return SIZE_MAX (the overflow indication),
+it complains about these call sites overflowing (since SIZE_MAX is
+greater than the default -Walloc-size-larger-than=PTRDIFF_MAX).  This
+isn't helpful since we already know a SIZE_MAX will be caught at
+run-time (this was an intentional design).  To deal with this, we must
+disable this check as it is both a false positive and redundant.  (Clang
+does not have this warning option.)
+
+Unfortunately, just checking the -Wno-alloc-size-larger-than is not
+sufficient to make the __alloc_size attribute behave correctly under
+older GCC versions.  The attribute itself must be disabled in those
+situations too, as there appears to be no way to reliably silence the
+SIZE_MAX constant expression cases for GCC versions less than 9.1:
+
+   In file included from ./include/linux/resource_ext.h:11,
+                    from ./include/linux/pci.h:40,
+                    from drivers/net/ethernet/intel/ixgbe/ixgbe.h:9,
+                    from drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c:4:
+   In function 'kmalloc_node',
+       inlined from 'ixgbe_alloc_q_vector' at ./include/linux/slab.h:743:9:
+   ./include/linux/slab.h:618:9: error: argument 1 value '18446744073709551615' exceeds maximum object size 9223372036854775807 [-Werror=alloc-size-larger-than=]
+     return __kmalloc_node(size, flags, node);
+            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   ./include/linux/slab.h: In function 'ixgbe_alloc_q_vector':
+   ./include/linux/slab.h:455:7: note: in a call to allocation function '__kmalloc_node' declared here
+    void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_slab_alignment __malloc;
+          ^~~~~~~~~~~~~~
+
+Specifically:
+ '-Wno-alloc-size-larger-than' is not correctly handled by GCC < 9.1
+    https://godbolt.org/z/hqsfG7q84 (doesn't disable)
+    https://godbolt.org/z/P9jdrPTYh (doesn't admit to not knowing about option)
+    https://godbolt.org/z/465TPMWKb (only warns when other warnings appear)
+
+ '-Walloc-size-larger-than=18446744073709551615' is not handled by GCC < 8.2
+    https://godbolt.org/z/73hh1EPxz (ignores numeric value)
+
+Since anything marked with __alloc_size would also qualify for marking
+with __malloc, just include __malloc along with it to avoid redundant
+markings.  (Suggested by Linus Torvalds.)
+
+Finally, make sure checkpatch.pl doesn't get confused about finding the
+__alloc_size attribute on functions.  (Thanks to Joe Perches.)
+
+Link: https://lkml.kernel.org/r/20210930222704.2631604-3-keescook@chromium.org
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Tested-by: Randy Dunlap <rdunlap@infradead.org>
+Cc: Andy Whitcroft <apw@canonical.com>
+Cc: Christoph Lameter <cl@linux.com>
+Cc: Daniel Micay <danielmicay@gmail.com>
+Cc: David Rientjes <rientjes@google.com>
+Cc: Dennis Zhou <dennis@kernel.org>
+Cc: Dwaipayan Ray <dwaipayanray1@gmail.com>
+Cc: Joe Perches <joe@perches.com>
+Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
+Cc: Lukas Bulwahn <lukas.bulwahn@gmail.com>
+Cc: Pekka Enberg <penberg@kernel.org>
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Alexandre Bounine <alex.bou9@gmail.com>
+Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
+Cc: Ira Weiny <ira.weiny@intel.com>
+Cc: Jing Xiangfeng <jingxiangfeng@huawei.com>
+Cc: John Hubbard <jhubbard@nvidia.com>
+Cc: kernel test robot <lkp@intel.com>
+Cc: Matt Porter <mporter@kernel.crashing.org>
+Cc: Miguel Ojeda <ojeda@kernel.org>
+Cc: Nathan Chancellor <nathan@kernel.org>
+Cc: Nick Desaulniers <ndesaulniers@google.com>
+Cc: Souptick Joarder <jrdr.linux@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Makefile                            | 15 +++++++++++++++
+ include/linux/compiler-gcc.h        |  8 ++++++++
+ include/linux/compiler_attributes.h | 10 ++++++++++
+ include/linux/compiler_types.h      | 12 ++++++++++++
+ scripts/checkpatch.pl               |  3 ++-
+ 5 files changed, 47 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index c7750d260a55..397fb08d17f2 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1011,6 +1011,21 @@ ifdef CONFIG_CC_IS_GCC
+ KBUILD_CFLAGS += -Wno-maybe-uninitialized
+ endif
++ifdef CONFIG_CC_IS_GCC
++# The allocators already balk at large sizes, so silence the compiler
++# warnings for bounds checks involving those possible values. While
++# -Wno-alloc-size-larger-than would normally be used here, earlier versions
++# of gcc (<9.1) weirdly don't handle the option correctly when _other_
++# warnings are produced (?!). Using -Walloc-size-larger-than=SIZE_MAX
++# doesn't work (as it is documented to), silently resolving to "0" prior to
++# version 9.1 (and producing an error more recently). Numeric values larger
++# than PTRDIFF_MAX also don't work prior to version 9.1, which are silently
++# ignored, continuing to default to PTRDIFF_MAX. So, left with no other
++# choice, we must perform a versioned check to disable this warning.
++# https://lore.kernel.org/lkml/20210824115859.187f272f@canb.auug.org.au
++KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0901, -Wno-alloc-size-larger-than)
++endif
++
+ # disable invalid "can't wrap" optimizations for signed / pointers
+ KBUILD_CFLAGS += -fno-strict-overflow
+diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
+index bd2b881c6b63..b9d5f9c373a0 100644
+--- a/include/linux/compiler-gcc.h
++++ b/include/linux/compiler-gcc.h
+@@ -144,3 +144,11 @@
+ #else
+ #define __diag_GCC_8(s)
+ #endif
++
++/*
++ * Prior to 9.1, -Wno-alloc-size-larger-than (and therefore the "alloc_size"
++ * attribute) do not work, and must be disabled.
++ */
++#if GCC_VERSION < 90100
++#undef __alloc_size__
++#endif
+diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h
+index e6ec63403965..3de06a8fae73 100644
+--- a/include/linux/compiler_attributes.h
++++ b/include/linux/compiler_attributes.h
+@@ -33,6 +33,15 @@
+ #define __aligned(x)                    __attribute__((__aligned__(x)))
+ #define __aligned_largest               __attribute__((__aligned__))
++/*
++ * Note: do not use this directly. Instead, use __alloc_size() since it is conditionally
++ * available and includes other attributes.
++ *
++ *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alloc_005fsize-function-attribute
++ * clang: https://clang.llvm.org/docs/AttributeReference.html#alloc-size
++ */
++#define __alloc_size__(x, ...)                __attribute__((__alloc_size__(x, ## __VA_ARGS__)))
++
+ /*
+  * Note: users of __always_inline currently do not write "inline" themselves,
+  * which seems to be required by gcc to apply the attribute according
+@@ -153,6 +162,7 @@
+ /*
+  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute
++ * clang: https://clang.llvm.org/docs/AttributeReference.html#malloc
+  */
+ #define __malloc                        __attribute__((__malloc__))
+diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
+index b6ff83a714ca..4f2203c4a257 100644
+--- a/include/linux/compiler_types.h
++++ b/include/linux/compiler_types.h
+@@ -250,6 +250,18 @@ struct ftrace_likely_data {
+ # define __cficanonical
+ #endif
++/*
++ * Any place that could be marked with the "alloc_size" attribute is also
++ * a place to be marked with the "malloc" attribute. Do this as part of the
++ * __alloc_size macro to avoid redundant attributes and to avoid missing a
++ * __malloc marking.
++ */
++#ifdef __alloc_size__
++# define __alloc_size(x, ...) __alloc_size__(x, ## __VA_ARGS__) __malloc
++#else
++# define __alloc_size(x, ...) __malloc
++#endif
++
+ #ifndef asm_volatile_goto
+ #define asm_volatile_goto(x...) asm goto(x)
+ #endif
+diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
+index c27d2312cfc3..88cb294dc447 100755
+--- a/scripts/checkpatch.pl
++++ b/scripts/checkpatch.pl
+@@ -489,7 +489,8 @@ our $Attribute     = qr{
+                       ____cacheline_aligned|
+                       ____cacheline_aligned_in_smp|
+                       ____cacheline_internodealigned_in_smp|
+-                      __weak
++                      __weak|
++                      __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\)
+                 }x;
+ our $Modifier;
+ our $Inline   = qr{inline|__always_inline|noinline|__inline|__inline__};
+-- 
+2.35.1
+
diff --git a/queue-5.15/cxl-port-hold-port-reference-until-decoder-release.patch b/queue-5.15/cxl-port-hold-port-reference-until-decoder-release.patch
new file mode 100644 (file)
index 0000000..fa85f10
--- /dev/null
@@ -0,0 +1,72 @@
+From 1ebc4a4f17a863ed464c14b72a5d167428638081 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Feb 2022 16:25:11 -0800
+Subject: cxl/port: Hold port reference until decoder release
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+[ Upstream commit 74be98774dfbc5b8b795db726bd772e735d2edd4 ]
+
+KASAN + DEBUG_KOBJECT_RELEASE reports a potential use-after-free in
+cxl_decoder_release() where it goes to reference its parent, a cxl_port,
+to free its id back to port->decoder_ida.
+
+ BUG: KASAN: use-after-free in to_cxl_port+0x18/0x90 [cxl_core]
+ Read of size 8 at addr ffff888119270908 by task kworker/35:2/379
+
+ CPU: 35 PID: 379 Comm: kworker/35:2 Tainted: G           OE     5.17.0-rc2+ #198
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
+ Workqueue: events kobject_delayed_cleanup
+ Call Trace:
+  <TASK>
+  dump_stack_lvl+0x59/0x73
+  print_address_description.constprop.0+0x1f/0x150
+  ? to_cxl_port+0x18/0x90 [cxl_core]
+  kasan_report.cold+0x83/0xdf
+  ? to_cxl_port+0x18/0x90 [cxl_core]
+  to_cxl_port+0x18/0x90 [cxl_core]
+  cxl_decoder_release+0x2a/0x60 [cxl_core]
+  device_release+0x5f/0x100
+  kobject_cleanup+0x80/0x1c0
+
+The device core only guarantees parent lifetime until all children are
+unregistered. If a child needs a parent to complete its ->release()
+callback that child needs to hold a reference to extend the lifetime of
+the parent.
+
+Fixes: 40ba17afdfab ("cxl/acpi: Introduce cxl_decoder objects")
+Reported-by: Ben Widawsky <ben.widawsky@intel.com>
+Tested-by: Ben Widawsky <ben.widawsky@intel.com>
+Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
+Link: https://lore.kernel.org/r/164505751190.4175768.13324905271463416712.stgit@dwillia2-desk3.amr.corp.intel.com
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cxl/core/bus.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c
+index 267d8042bec2..0987a6423ee0 100644
+--- a/drivers/cxl/core/bus.c
++++ b/drivers/cxl/core/bus.c
+@@ -182,6 +182,7 @@ static void cxl_decoder_release(struct device *dev)
+       ida_free(&port->decoder_ida, cxld->id);
+       kfree(cxld);
++      put_device(&port->dev);
+ }
+ static const struct device_type cxl_decoder_switch_type = {
+@@ -481,6 +482,9 @@ cxl_decoder_alloc(struct cxl_port *port, int nr_targets, resource_size_t base,
+       if (rc < 0)
+               goto err;
++      /* need parent to stick around to release the id */
++      get_device(&port->dev);
++
+       *cxld = (struct cxl_decoder) {
+               .id = rc,
+               .range = {
+-- 
+2.35.1
+
diff --git a/queue-5.15/dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch b/queue-5.15/dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch
new file mode 100644 (file)
index 0000000..7903856
--- /dev/null
@@ -0,0 +1,93 @@
+From 095e8ce5c8f15213fdfd6c5a5b81d57c648bc7b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Jul 2021 09:58:57 +0200
+Subject: dma-buf/poll: Get a file reference for outstanding fence callbacks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michel Dänzer <mdaenzer@redhat.com>
+
+[ Upstream commit ff2d23843f7fb4f13055be5a4a9a20ddd04e6e9c ]
+
+This makes sure we don't hit the
+
+       BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
+
+in dma_buf_release, which could be triggered by user space closing the
+dma-buf file description while there are outstanding fence callbacks
+from dma_buf_poll.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michel Dänzer <mdaenzer@redhat.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210723075857.4065-1-michel@daenzer.net
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma-buf/dma-buf.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
+index f9217e300eea..968c3df2810e 100644
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -67,12 +67,9 @@ static void dma_buf_release(struct dentry *dentry)
+       BUG_ON(dmabuf->vmapping_counter);
+       /*
+-       * Any fences that a dma-buf poll can wait on should be signaled
+-       * before releasing dma-buf. This is the responsibility of each
+-       * driver that uses the reservation objects.
+-       *
+-       * If you hit this BUG() it means someone dropped their ref to the
+-       * dma-buf while still having pending operation to the buffer.
++       * If you hit this BUG() it could mean:
++       * * There's a file reference imbalance in dma_buf_poll / dma_buf_poll_cb or somewhere else
++       * * dmabuf->cb_in/out.active are non-0 despite no pending fence callback
+        */
+       BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
+@@ -200,6 +197,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
+ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
+ {
+       struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb;
++      struct dma_buf *dmabuf = container_of(dcb->poll, struct dma_buf, poll);
+       unsigned long flags;
+       spin_lock_irqsave(&dcb->poll->lock, flags);
+@@ -207,6 +205,8 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
+       dcb->active = 0;
+       spin_unlock_irqrestore(&dcb->poll->lock, flags);
+       dma_fence_put(fence);
++      /* Paired with get_file in dma_buf_poll */
++      fput(dmabuf->file);
+ }
+ static bool dma_buf_poll_shared(struct dma_resv *resv,
+@@ -282,8 +282,12 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
+               spin_unlock_irq(&dmabuf->poll.lock);
+               if (events & EPOLLOUT) {
++                      /* Paired with fput in dma_buf_poll_cb */
++                      get_file(dmabuf->file);
++
+                       if (!dma_buf_poll_shared(resv, dcb) &&
+                           !dma_buf_poll_excl(resv, dcb))
++
+                               /* No callback queued, wake up any other waiters */
+                               dma_buf_poll_cb(NULL, &dcb->cb);
+                       else
+@@ -303,6 +307,9 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
+               spin_unlock_irq(&dmabuf->poll.lock);
+               if (events & EPOLLIN) {
++                      /* Paired with fput in dma_buf_poll_cb */
++                      get_file(dmabuf->file);
++
+                       if (!dma_buf_poll_excl(resv, dcb))
+                               /* No callback queued, wake up any other waiters */
+                               dma_buf_poll_cb(NULL, &dcb->cb);
+-- 
+2.35.1
+
diff --git a/queue-5.15/drbd-add-error-handling-support-for-add_disk.patch b/queue-5.15/drbd-add-error-handling-support-for-add_disk.patch
new file mode 100644 (file)
index 0000000..b938b82
--- /dev/null
@@ -0,0 +1,47 @@
+From 24922376eeda8b7c9c54bbcdf28021e3325f33b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Sep 2021 15:00:59 -0700
+Subject: drbd: add error handling support for add_disk()
+
+From: Luis Chamberlain <mcgrof@kernel.org>
+
+[ Upstream commit e92ab4eda516a5bfd96c087282ebe9521deba4f4 ]
+
+We never checked for errors on add_disk() as this function
+returned void. Now that this is fixed, use the shiny new
+error handling.
+
+Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/drbd/drbd_main.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
+index 8ba2fe356f01..ae6a136d278e 100644
+--- a/drivers/block/drbd/drbd_main.c
++++ b/drivers/block/drbd/drbd_main.c
+@@ -2798,7 +2798,9 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+               goto out_idr_remove_vol;
+       }
+-      add_disk(disk);
++      err = add_disk(disk);
++      if (err)
++              goto out_cleanup_disk;
+       /* inherit the connection state */
+       device->state.conn = first_connection(resource)->cstate;
+@@ -2812,6 +2814,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+       drbd_debugfs_device_add(device);
+       return NO_ERROR;
++out_cleanup_disk:
++      blk_cleanup_disk(disk);
+ out_idr_remove_vol:
+       idr_remove(&connection->peer_devices, vnr);
+ out_idr_remove_from_resource:
+-- 
+2.35.1
+
diff --git a/queue-5.15/drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch b/queue-5.15/drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch
new file mode 100644 (file)
index 0000000..501999d
--- /dev/null
@@ -0,0 +1,69 @@
+From b95039363a3ed89cf8d474e1d691d9dbf5322b73 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Apr 2022 21:04:44 +0200
+Subject: drbd: fix an invalid memory access caused by incorrect use of list
+ iterator
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Xiaomeng Tong <xiam0nd.tong@gmail.com>
+
+[ Upstream commit ae4d37b5df749926891583d42a6801b5da11e3c1 ]
+
+The bug is here:
+       idr_remove(&connection->peer_devices, vnr);
+
+If the previous for_each_connection() don't exit early (no goto hit
+inside the loop), the iterator 'connection' after the loop will be a
+bogus pointer to an invalid structure object containing the HEAD
+(&resource->connections). As a result, the use of 'connection' above
+will lead to a invalid memory access (including a possible invalid free
+as idr_remove could call free_layer).
+
+The original intention should have been to remove all peer_devices,
+but the following lines have already done the work. So just remove
+this line and the unneeded label, to fix this bug.
+
+Cc: stable@vger.kernel.org
+Fixes: c06ece6ba6f1b ("drbd: Turn connection->volumes into connection->peer_devices")
+Signed-off-by: Xiaomeng Tong <xiam0nd.tong@gmail.com>
+Reviewed-by: Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
+Reviewed-by: Lars Ellenberg <lars.ellenberg@linbit.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/drbd/drbd_main.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
+index b91d2a9dc238..d59af26d7703 100644
+--- a/drivers/block/drbd/drbd_main.c
++++ b/drivers/block/drbd/drbd_main.c
+@@ -2795,12 +2795,12 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+       if (init_submitter(device)) {
+               err = ERR_NOMEM;
+-              goto out_idr_remove_vol;
++              goto out_idr_remove_from_resource;
+       }
+       err = add_disk(disk);
+       if (err)
+-              goto out_idr_remove_vol;
++              goto out_idr_remove_from_resource;
+       /* inherit the connection state */
+       device->state.conn = first_connection(resource)->cstate;
+@@ -2814,8 +2814,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+       drbd_debugfs_device_add(device);
+       return NO_ERROR;
+-out_idr_remove_vol:
+-      idr_remove(&connection->peer_devices, vnr);
+ out_idr_remove_from_resource:
+       for_each_connection(connection, resource) {
+               peer_device = idr_remove(&connection->peer_devices, vnr);
+-- 
+2.35.1
+
diff --git a/queue-5.15/drbd-fix-double-free-problem-in-drbd_create_device.patch b/queue-5.15/drbd-fix-double-free-problem-in-drbd_create_device.patch
new file mode 100644 (file)
index 0000000..d50a6bd
--- /dev/null
@@ -0,0 +1,50 @@
+From baf6c215912ca443adde48acb4bf135c9e28f41d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Nov 2021 16:07:09 +0800
+Subject: drbd: Fix double free problem in drbd_create_device
+
+From: Wu Bo <wubo40@huawei.com>
+
+[ Upstream commit 27548088ac628109f70eb0b1eb521d035844dba8 ]
+
+In drbd_create_device(), the 'out_no_io_page' lable has called
+blk_cleanup_disk() when return failed.
+
+So remove the 'out_cleanup_disk' lable to avoid double free the
+disk pointer.
+
+Fixes: e92ab4eda516 ("drbd: add error handling support for add_disk()")
+Signed-off-by: Wu Bo <wubo40@huawei.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/1636013229-26309-1-git-send-email-wubo40@huawei.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/drbd/drbd_main.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
+index ae6a136d278e..b91d2a9dc238 100644
+--- a/drivers/block/drbd/drbd_main.c
++++ b/drivers/block/drbd/drbd_main.c
+@@ -2800,7 +2800,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+       err = add_disk(disk);
+       if (err)
+-              goto out_cleanup_disk;
++              goto out_idr_remove_vol;
+       /* inherit the connection state */
+       device->state.conn = first_connection(resource)->cstate;
+@@ -2814,8 +2814,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+       drbd_debugfs_device_add(device);
+       return NO_ERROR;
+-out_cleanup_disk:
+-      blk_cleanup_disk(disk);
+ out_idr_remove_vol:
+       idr_remove(&connection->peer_devices, vnr);
+ out_idr_remove_from_resource:
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch b/queue-5.15/drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch
new file mode 100644 (file)
index 0000000..3dac023
--- /dev/null
@@ -0,0 +1,96 @@
+From 63f6623c541b73e989c52dd8b907d577affd482c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Mar 2022 13:10:31 +0530
+Subject: drm/amd/display: Fix by adding FPU protection for
+ dcn30_internal_validate_bw
+
+From: CHANDAN VURDIGERE NATARAJ <chandan.vurdigerenataraj@amd.com>
+
+[ Upstream commit 50e6cb3fd2cde554db646282ea10df7236e6493c ]
+
+[Why]
+Below general protection fault observed when WebGL Aquarium is run for
+longer duration. If drm debug logs are enabled and set to 0x1f then the
+issue is observed within 10 minutes of run.
+
+[  100.717056] general protection fault, probably for non-canonical address 0x2d33302d32323032: 0000 [#1] PREEMPT SMP NOPTI
+[  100.727921] CPU: 3 PID: 1906 Comm: DrmThread Tainted: G        W         5.15.30 #12 d726c6a2d6ebe5cf9223931cbca6892f916fe18b
+[  100.754419] RIP: 0010:CalculateSwathWidth+0x1f7/0x44f
+[  100.767109] Code: 00 00 00 f2 42 0f 11 04 f0 48 8b 85 88 00 00 00 f2 42 0f 10 04 f0 48 8b 85 98 00 00 00 f2 42 0f 11 04 f0 48 8b 45 10 0f 57 c0 <f3> 42 0f 2a 04 b0 0f 57 c9 f3 43 0f 2a 0c b4 e8 8c e2 f3 ff 48 8b
+[  100.781269] RSP: 0018:ffffa9230079eeb0 EFLAGS: 00010246
+[  100.812528] RAX: 2d33302d32323032 RBX: 0000000000000500 RCX: 0000000000000000
+[  100.819656] RDX: 0000000000000001 RSI: ffff99deb712c49c RDI: 0000000000000000
+[  100.826781] RBP: ffffa9230079ef50 R08: ffff99deb712460c R09: ffff99deb712462c
+[  100.833907] R10: ffff99deb7124940 R11: ffff99deb7124d70 R12: ffff99deb712ae44
+[  100.841033] R13: 0000000000000001 R14: 0000000000000000 R15: ffffa9230079f0a0
+[  100.848159] FS:  00007af121212640(0000) GS:ffff99deba780000(0000) knlGS:0000000000000000
+[  100.856240] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  100.861980] CR2: 0000209000fe1000 CR3: 000000011b18c000 CR4: 0000000000350ee0
+[  100.869106] Call Trace:
+[  100.871555]  <TASK>
+[  100.873655]  ? asm_sysvec_reschedule_ipi+0x12/0x20
+[  100.878449]  CalculateSwathAndDETConfiguration+0x1a3/0x6dd
+[  100.883937]  dml31_ModeSupportAndSystemConfigurationFull+0x2ce4/0x76da
+[  100.890467]  ? kallsyms_lookup_buildid+0xc8/0x163
+[  100.895173]  ? kallsyms_lookup_buildid+0xc8/0x163
+[  100.899874]  ? __sprint_symbol+0x80/0x135
+[  100.903883]  ? dm_update_plane_state+0x3f9/0x4d2
+[  100.908500]  ? symbol_string+0xb7/0xde
+[  100.912250]  ? number+0x145/0x29b
+[  100.915566]  ? vsnprintf+0x341/0x5ff
+[  100.919141]  ? desc_read_finalized_seq+0x39/0x87
+[  100.923755]  ? update_load_avg+0x1b9/0x607
+[  100.927849]  ? compute_mst_dsc_configs_for_state+0x7d/0xd5b
+[  100.933416]  ? fetch_pipe_params+0xa4d/0xd0c
+[  100.937686]  ? dc_fpu_end+0x3d/0xa8
+[  100.941175]  dml_get_voltage_level+0x16b/0x180
+[  100.945619]  dcn30_internal_validate_bw+0x10e/0x89b
+[  100.950495]  ? dcn31_validate_bandwidth+0x68/0x1fc
+[  100.955285]  ? resource_build_scaling_params+0x98b/0xb8c
+[  100.960595]  ? dcn31_validate_bandwidth+0x68/0x1fc
+[  100.965384]  dcn31_validate_bandwidth+0x9a/0x1fc
+[  100.970001]  dc_validate_global_state+0x238/0x295
+[  100.974703]  amdgpu_dm_atomic_check+0x9c1/0xbce
+[  100.979235]  ? _printk+0x59/0x73
+[  100.982467]  drm_atomic_check_only+0x403/0x78b
+[  100.986912]  drm_mode_atomic_ioctl+0x49b/0x546
+[  100.991358]  ? drm_ioctl+0x1c1/0x3b3
+[  100.994936]  ? drm_atomic_set_property+0x92a/0x92a
+[  100.999725]  drm_ioctl_kernel+0xdc/0x149
+[  101.003648]  drm_ioctl+0x27f/0x3b3
+[  101.007051]  ? drm_atomic_set_property+0x92a/0x92a
+[  101.011842]  amdgpu_drm_ioctl+0x49/0x7d
+[  101.015679]  __se_sys_ioctl+0x7c/0xb8
+[  101.015685]  do_syscall_64+0x5f/0xb8
+[  101.015690]  ? __irq_exit_rcu+0x34/0x96
+
+[How]
+It calles populate_dml_pipes which uses doubles to initialize.
+Adding FPU protection avoids context switch and probable loss of vba context
+as there is potential contention while drm debug logs are enabled.
+
+Signed-off-by: CHANDAN VURDIGERE NATARAJ <chandan.vurdigerenataraj@amd.com>
+Reviewed-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+index 7aadb35a3079..e224c5213258 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+@@ -1813,7 +1813,9 @@ bool dcn31_validate_bandwidth(struct dc *dc,
+       BW_VAL_TRACE_COUNT();
++      DC_FP_START();
+       out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
++      DC_FP_END();
+       // Disable fast_validate to set min dcfclk in alculate_wm_and_dlg
+       if (pipe_cnt == 0)
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch b/queue-5.15/drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch
new file mode 100644 (file)
index 0000000..0dc3da0
--- /dev/null
@@ -0,0 +1,154 @@
+From 74991c0a3852c85aaed70719363488ad5916b3da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Aug 2021 11:38:44 -0400
+Subject: drm/amd/display: Set min dcfclk if pipe count is 0
+
+From: Michael Strauss <michael.strauss@amd.com>
+
+[ Upstream commit bc204778b4032b336cb3bde85bea852d79e7e389 ]
+
+[WHY]
+Clocks don't get recalculated in 0 stream/0 pipe configs,
+blocking S0i3 if dcfclk gets high enough
+
+[HOW]
+Create DCN31 copy of DCN30 bandwidth validation func which
+doesn't entirely skip validation in 0 pipe scenarios
+
+Override dcfclk to vlevel 0/min value during validation if pipe
+count is 0
+
+Reviewed-by: Eric Yang <Eric.Yang2@amd.com>
+Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
+Signed-off-by: Michael Strauss <michael.strauss@amd.com>
+Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/amd/display/dc/dcn30/dcn30_resource.c |  2 +-
+ .../drm/amd/display/dc/dcn30/dcn30_resource.h |  7 +++
+ .../drm/amd/display/dc/dcn31/dcn31_resource.c | 63 ++++++++++++++++++-
+ 3 files changed, 70 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+index 0294d0cc4759..735c92a5aa36 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+@@ -1856,7 +1856,7 @@ static struct pipe_ctx *dcn30_find_split_pipe(
+       return pipe;
+ }
+-static noinline bool dcn30_internal_validate_bw(
++noinline bool dcn30_internal_validate_bw(
+               struct dc *dc,
+               struct dc_state *context,
+               display_e2e_pipe_params_st *pipes,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
+index b754b89beadf..b92e4cc0232f 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
+@@ -55,6 +55,13 @@ unsigned int dcn30_calc_max_scaled_time(
+ bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context,
+               bool fast_validate);
++bool dcn30_internal_validate_bw(
++              struct dc *dc,
++              struct dc_state *context,
++              display_e2e_pipe_params_st *pipes,
++              int *pipe_cnt_out,
++              int *vlevel_out,
++              bool fast_validate);
+ void dcn30_calculate_wm_and_dlg(
+               struct dc *dc, struct dc_state *context,
+               display_e2e_pipe_params_st *pipes,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+index b60ab3cc0f11..7aadb35a3079 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+@@ -1664,6 +1664,15 @@ static void dcn31_calculate_wm_and_dlg_fp(
+       if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
+               dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
++      /* We don't recalculate clocks for 0 pipe configs, which can block
++       * S0i3 as high clocks will block low power states
++       * Override any clocks that can block S0i3 to min here
++       */
++      if (pipe_cnt == 0) {
++              context->bw_ctx.bw.dcn.clk.dcfclk_khz = dcfclk; // always should be vlevel 0
++              return;
++      }
++
+       pipes[0].clks_cfg.voltage = vlevel;
+       pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+       pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+@@ -1789,6 +1798,58 @@ static void dcn31_calculate_wm_and_dlg(
+       DC_FP_END();
+ }
++bool dcn31_validate_bandwidth(struct dc *dc,
++              struct dc_state *context,
++              bool fast_validate)
++{
++      bool out = false;
++
++      BW_VAL_TRACE_SETUP();
++
++      int vlevel = 0;
++      int pipe_cnt = 0;
++      display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
++      DC_LOGGER_INIT(dc->ctx->logger);
++
++      BW_VAL_TRACE_COUNT();
++
++      out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
++
++      // Disable fast_validate to set min dcfclk in alculate_wm_and_dlg
++      if (pipe_cnt == 0)
++              fast_validate = false;
++
++      if (!out)
++              goto validate_fail;
++
++      BW_VAL_TRACE_END_VOLTAGE_LEVEL();
++
++      if (fast_validate) {
++              BW_VAL_TRACE_SKIP(fast);
++              goto validate_out;
++      }
++
++      dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
++
++      BW_VAL_TRACE_END_WATERMARKS();
++
++      goto validate_out;
++
++validate_fail:
++      DC_LOG_WARNING("Mode Validation Warning: %s failed alidation.\n",
++              dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
++
++      BW_VAL_TRACE_SKIP(fail);
++      out = false;
++
++validate_out:
++      kfree(pipes);
++
++      BW_VAL_TRACE_FINISH();
++
++      return out;
++}
++
+ static struct dc_cap_funcs cap_funcs = {
+       .get_dcc_compression_cap = dcn20_get_dcc_compression_cap
+ };
+@@ -1871,7 +1932,7 @@ static struct resource_funcs dcn31_res_pool_funcs = {
+       .link_encs_assign = link_enc_cfg_link_encs_assign,
+       .link_enc_unassign = link_enc_cfg_link_enc_unassign,
+       .panel_cntl_create = dcn31_panel_cntl_create,
+-      .validate_bandwidth = dcn30_validate_bandwidth,
++      .validate_bandwidth = dcn31_validate_bandwidth,
+       .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg,
+       .update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
+       .populate_dml_pipes = dcn31_populate_dml_pipes_from_context,
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch b/queue-5.15/drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch
new file mode 100644 (file)
index 0000000..97abb5e
--- /dev/null
@@ -0,0 +1,164 @@
+From 3865f7a47bd4d4328d9e60b58e5072710cd533ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Feb 2022 23:19:58 -0600
+Subject: drm/amd: Refactor `amdgpu_aspm` to be evaluated per device
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit 0ab5d711ec74d9e60673900974806b7688857947 ]
+
+Evaluating `pcie_aspm_enabled` as part of driver probe has the implication
+that if one PCIe bridge with an AMD GPU connected doesn't support ASPM
+then none of them do.  This is an invalid assumption as the PCIe core will
+configure ASPM for individual PCIe bridges.
+
+Create a new helper function that can be called by individual dGPUs to
+react to the `amdgpu_aspm` module parameter without having negative results
+for other dGPUs on the PCIe bus.
+
+Suggested-by: Lijo Lazar <lijo.lazar@amd.com>
+Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h           |  1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c    | 25 +++++++++++++++++++
+ drivers/gpu/drm/amd/amdgpu/cik.c              |  2 +-
+ drivers/gpu/drm/amd/amdgpu/nv.c               |  2 +-
+ drivers/gpu/drm/amd/amdgpu/si.c               |  2 +-
+ drivers/gpu/drm/amd/amdgpu/soc15.c            |  2 +-
+ drivers/gpu/drm/amd/amdgpu/vi.c               |  2 +-
+ .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c   |  2 +-
+ 8 files changed, 32 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index 2eebefd26fa8..5f95d03fd46a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -1285,6 +1285,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
+ void amdgpu_device_pci_config_reset(struct amdgpu_device *adev);
+ int amdgpu_device_pci_reset(struct amdgpu_device *adev);
+ bool amdgpu_device_need_post(struct amdgpu_device *adev);
++bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev);
+ void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes,
+                                 u64 num_vis_bytes);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index a926b5ebbfdf..d1af709cc7dc 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -1309,6 +1309,31 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev)
+       return true;
+ }
++/**
++ * amdgpu_device_should_use_aspm - check if the device should program ASPM
++ *
++ * @adev: amdgpu_device pointer
++ *
++ * Confirm whether the module parameter and pcie bridge agree that ASPM should
++ * be set for this device.
++ *
++ * Returns true if it should be used or false if not.
++ */
++bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
++{
++      switch (amdgpu_aspm) {
++      case -1:
++              break;
++      case 0:
++              return false;
++      case 1:
++              return true;
++      default:
++              return false;
++      }
++      return pcie_aspm_enabled(adev->pdev);
++}
++
+ /* if we get transitioned to only one device, take VGA back */
+ /**
+  * amdgpu_device_vga_set_decode - enable/disable vga decode
+diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
+index f10ce740a29c..de6d10390ab2 100644
+--- a/drivers/gpu/drm/amd/amdgpu/cik.c
++++ b/drivers/gpu/drm/amd/amdgpu/cik.c
+@@ -1719,7 +1719,7 @@ static void cik_program_aspm(struct amdgpu_device *adev)
+       bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+       bool disable_clkreq = false;
+-      if (amdgpu_aspm == 0)
++      if (!amdgpu_device_should_use_aspm(adev))
+               return;
+       if (pci_is_root_bus(adev->pdev->bus))
+diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
+index 9cbed9a8f1c0..6e277236b44f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/nv.c
++++ b/drivers/gpu/drm/amd/amdgpu/nv.c
+@@ -584,7 +584,7 @@ static void nv_pcie_gen3_enable(struct amdgpu_device *adev)
+ static void nv_program_aspm(struct amdgpu_device *adev)
+ {
+-      if (!amdgpu_aspm)
++      if (!amdgpu_device_should_use_aspm(adev))
+               return;
+       if (!(adev->flags & AMD_IS_APU) &&
+diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
+index e6d2f74a7976..7f99e130acd0 100644
+--- a/drivers/gpu/drm/amd/amdgpu/si.c
++++ b/drivers/gpu/drm/amd/amdgpu/si.c
+@@ -2453,7 +2453,7 @@ static void si_program_aspm(struct amdgpu_device *adev)
+       bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+       bool disable_clkreq = false;
+-      if (amdgpu_aspm == 0)
++      if (!amdgpu_device_should_use_aspm(adev))
+               return;
+       if (adev->flags & AMD_IS_APU)
+diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
+index 6439d5c3d8d8..bdb47ae96ce6 100644
+--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
++++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
+@@ -689,7 +689,7 @@ static void soc15_pcie_gen3_enable(struct amdgpu_device *adev)
+ static void soc15_program_aspm(struct amdgpu_device *adev)
+ {
+-      if (!amdgpu_aspm)
++      if (!amdgpu_device_should_use_aspm(adev))
+               return;
+       if (!(adev->flags & AMD_IS_APU) &&
+diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
+index 6645ebbd2696..039b90cdc3bc 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vi.c
++++ b/drivers/gpu/drm/amd/amdgpu/vi.c
+@@ -1140,7 +1140,7 @@ static void vi_program_aspm(struct amdgpu_device *adev)
+       bool bL1SS = false;
+       bool bClkReqSupport = true;
+-      if (!amdgpu_aspm)
++      if (!amdgpu_device_should_use_aspm(adev))
+               return;
+       if (adev->flags & AMD_IS_APU ||
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+index 574a9d7f7a5e..918d5c7c2328 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+@@ -338,7 +338,7 @@ sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu,
+       if (smu->dc_controlled_by_gpio)
+        *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT);
+-      if (amdgpu_aspm)
++      if (amdgpu_device_should_use_aspm(adev))
+               *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT);
+       return 0;
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch b/queue-5.15/drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch
new file mode 100644 (file)
index 0000000..7687aee
--- /dev/null
@@ -0,0 +1,40 @@
+From bf8ea95fb64e1e9fbebf251f5d186d240de57296 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 27 Mar 2022 19:07:13 +0800
+Subject: drm/amd/vcn: fix an error msg on vcn 3.0
+
+From: tiancyin <tianci.yin@amd.com>
+
+[ Upstream commit 425d7a87e54ee358f580eaf10cf28dc95f7121c1 ]
+
+Some video card has more than one vcn instance, passing 0 to
+vcn_v3_0_pause_dpg_mode is incorrect.
+
+Error msg:
+Register(1) [mmUVD_POWER_STATUS] failed to reach value
+0x00000001 != 0x00000002
+
+Reviewed-by: James Zhu <James.Zhu@amd.com>
+Signed-off-by: tiancyin <tianci.yin@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+index 6e56bef4fdf8..1310617f030f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+@@ -1511,7 +1511,7 @@ static int vcn_v3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
+       struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__UNPAUSE};
+       uint32_t tmp;
+-      vcn_v3_0_pause_dpg_mode(adev, 0, &state);
++      vcn_v3_0_pause_dpg_mode(adev, inst_idx, &state);
+       /* Wait for power status to be 1 */
+       SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS, 1,
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch b/queue-5.15/drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch
new file mode 100644 (file)
index 0000000..1d9c763
--- /dev/null
@@ -0,0 +1,62 @@
+From c33a17fe4004dfa57beeec79734d66651652654e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Aug 2021 17:18:53 -0400
+Subject: drm/amdgpu: bind to any 0x1002 PCI diplay class device
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit eb4fd29afd4aa1c98d882800ceeee7d1f5262803 ]
+
+Bind to all 0x1002 GPU devices.
+
+For now we explicitly return -ENODEV for generic bindings.
+Remove this check once IP discovery based checking is in place.
+
+v2: rebase (Alex)
+
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index f65b4b233ffb..c294081022bd 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -1952,6 +1952,16 @@ static const struct pci_device_id pciidlist[] = {
+       {0x1002, 0x7424, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY},
+       {0x1002, 0x743F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY},
++      { PCI_DEVICE(0x1002, PCI_ANY_ID),
++        .class = PCI_CLASS_DISPLAY_VGA << 8,
++        .class_mask = 0xffffff,
++        .driver_data = 0 },
++
++      { PCI_DEVICE(0x1002, PCI_ANY_ID),
++        .class = PCI_CLASS_DISPLAY_OTHER << 8,
++        .class_mask = 0xffffff,
++        .driver_data = 0 },
++
+       {0, 0, 0}
+ };
+@@ -1999,6 +2009,11 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
+                       return -ENODEV;
+       }
++      if (flags == 0) {
++              DRM_INFO("Unsupported asic.  Remove me when IP discovery init is in place.\n");
++              return -ENODEV;
++      }
++
+       if (amdgpu_virtual_display ||
+           amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK))
+               supports_atomic = true;
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch b/queue-5.15/drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch
new file mode 100644 (file)
index 0000000..5c0bcf6
--- /dev/null
@@ -0,0 +1,38 @@
+From 33a59f2b018f781bebc5f322a3779f5581b866e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Jan 2022 09:59:29 -0500
+Subject: drm/amdgpu: drop flags check for CHIP_IP_DISCOVERY
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit d82ce3cd30aa28db3e94ffc36ebf0af2ff12801d ]
+
+Support for IP based discovery is in place now so this
+check is no longer required.
+
+Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index cb0b5972e7fd..a0dd4b41ba4a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -2009,11 +2009,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
+                       return -ENODEV;
+       }
+-      if (flags == CHIP_IP_DISCOVERY) {
+-              DRM_INFO("Unsupported asic.  Remove me when IP discovery init is in place.\n");
+-              return -ENODEV;
+-      }
+-
+       if (amdgpu_virtual_display ||
+           amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK))
+               supports_atomic = true;
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amdgpu-fix-rejecting-tahiti-gpus.patch b/queue-5.15/drm-amdgpu-fix-rejecting-tahiti-gpus.patch
new file mode 100644 (file)
index 0000000..4d8b840
--- /dev/null
@@ -0,0 +1,48 @@
+From c995df2c71b06e788627a83d76c565a56142bf76 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Jan 2022 07:51:41 +0100
+Subject: drm/amdgpu: Fix rejecting Tahiti GPUs
+
+From: Lukas Fink <lukas.fink1@gmail.com>
+
+[ Upstream commit 3993a799fc971bc9b918bd969aa55864447b5dde ]
+
+eb4fd29afd4a ("drm/amdgpu: bind to any 0x1002 PCI diplay class device") added
+generic bindings to amdgpu so that that it binds to all display class devices
+with VID 0x1002 and then rejects those in amdgpu_pci_probe.
+
+Unfortunately it reuses a driver_data value of 0 to detect those new bindings,
+which is already used to denote CHIP_TAHITI ASICs.
+
+The driver_data value given to those new bindings was changed in
+dd0761fd24ea1 ("drm/amdgpu: set CHIP_IP_DISCOVERY as the asic type by default")
+to CHIP_IP_DISCOVERY (=36), but it seems that the check in amdgpu_pci_probe
+was forgotten to be changed. Therefore, it still rejects Tahiti GPUs.
+
+Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1860
+Fixes: eb4fd29afd4a ("drm/amdgpu: bind to any 0x1002 PCI diplay class device")
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Lukas Fink <lukas.fink1@gmail.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index c294081022bd..cb0b5972e7fd 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -2009,7 +2009,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
+                       return -ENODEV;
+       }
+-      if (flags == 0) {
++      if (flags == CHIP_IP_DISCOVERY) {
+               DRM_INFO("Unsupported asic.  Remove me when IP discovery init is in place.\n");
+               return -ENODEV;
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch b/queue-5.15/drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch
new file mode 100644 (file)
index 0000000..173c8a9
--- /dev/null
@@ -0,0 +1,76 @@
+From 26701dacdcfb79758dd98eaad7a131d2ddffdf91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 Apr 2022 12:08:38 -0500
+Subject: drm/amdgpu: vi: disable ASPM on Intel Alder Lake based systems
+
+From: Richard Gong <richard.gong@amd.com>
+
+[ Upstream commit aa482ddca85a3485be0e7b83a0789dc4d987670b ]
+
+Active State Power Management (ASPM) feature is enabled since kernel 5.14.
+There are some AMD Volcanic Islands (VI) GFX cards, such as the WX3200 and
+RX640, that do not work with ASPM-enabled Intel Alder Lake based systems.
+Using these GFX cards as video/display output, Intel Alder Lake based
+systems will freeze after suspend/resume.
+
+The issue was originally reported on one system (Dell Precision 3660 with
+BIOS version 0.14.81), but was later confirmed to affect at least 4
+pre-production Alder Lake based systems.
+
+Add an extra check to disable ASPM on Intel Alder Lake based systems with
+the problematic AMD Volcanic Islands GFX cards.
+
+Fixes: 0064b0ce85bb ("drm/amd/pm: enable ASPM by default")
+Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1885
+Signed-off-by: Richard Gong <richard.gong@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/vi.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
+index 039b90cdc3bc..45f0188c4273 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vi.c
++++ b/drivers/gpu/drm/amd/amdgpu/vi.c
+@@ -81,6 +81,10 @@
+ #include "mxgpu_vi.h"
+ #include "amdgpu_dm.h"
++#if IS_ENABLED(CONFIG_X86)
++#include <asm/intel-family.h>
++#endif
++
+ #define ixPCIE_LC_L1_PM_SUBSTATE      0x100100C6
+ #define PCIE_LC_L1_PM_SUBSTATE__LC_L1_SUBSTATES_OVERRIDE_EN_MASK      0x00000001L
+ #define PCIE_LC_L1_PM_SUBSTATE__LC_PCI_PM_L1_2_OVERRIDE_MASK  0x00000002L
+@@ -1134,13 +1138,24 @@ static void vi_enable_aspm(struct amdgpu_device *adev)
+               WREG32_PCIE(ixPCIE_LC_CNTL, data);
+ }
++static bool aspm_support_quirk_check(void)
++{
++#if IS_ENABLED(CONFIG_X86)
++      struct cpuinfo_x86 *c = &cpu_data(0);
++
++      return !(c->x86 == 6 && c->x86_model == INTEL_FAM6_ALDERLAKE);
++#else
++      return true;
++#endif
++}
++
+ static void vi_program_aspm(struct amdgpu_device *adev)
+ {
+       u32 data, data1, orig;
+       bool bL1SS = false;
+       bool bClkReqSupport = true;
+-      if (!amdgpu_device_should_use_aspm(adev))
++      if (!amdgpu_device_should_use_aspm(adev) || !aspm_support_quirk_check())
+               return;
+       if (adev->flags & AMD_IS_APU ||
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-i915-disable-bonding-on-gen12-platforms.patch b/queue-5.15/drm-i915-disable-bonding-on-gen12-platforms.patch
new file mode 100644 (file)
index 0000000..ad0865b
--- /dev/null
@@ -0,0 +1,43 @@
+From c0b09353aaff042ff9843a6d0e02945862501c45 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Jul 2021 12:21:00 -0700
+Subject: drm/i915: Disable bonding on gen12+ platforms
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit ce7e75c7ef1bf8ea3d947da8c674d2f40fd7d734 ]
+
+Disable bonding on gen12+ platforms aside from ones already supported by
+the i915 - TGL, RKL, and ADL-S.
+
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: John Harrison <John.C.Harrison@Intel.com>
+Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210728192100.132425-1-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/gem/i915_gem_context.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+index ee0c0b712522..ba2e037a82e4 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+@@ -442,6 +442,13 @@ set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
+       u16 idx, num_bonds;
+       int err, n;
++      if (GRAPHICS_VER(i915) >= 12 && !IS_TIGERLAKE(i915) &&
++          !IS_ROCKETLAKE(i915) && !IS_ALDERLAKE_S(i915)) {
++              drm_dbg(&i915->drm,
++                      "Bonding on gen12+ aside from TGL, RKL, and ADL_S not supported\n");
++              return -ENODEV;
++      }
++
+       if (get_user(idx, &ext->virtual_index))
+               return -EFAULT;
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-i915-fix-a-race-between-vma-object-destruction-a.patch b/queue-5.15/drm-i915-fix-a-race-between-vma-object-destruction-a.patch
new file mode 100644 (file)
index 0000000..b9e10ec
--- /dev/null
@@ -0,0 +1,55 @@
+From 28dde823cbf891cb44f4fc3d6c8b5070226ad53c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jan 2022 12:56:22 +0100
+Subject: drm/i915: Fix a race between vma / object destruction and unbinding
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit bc1922e5d349db4be14c55513102c024c2ae8a50 ]
+
+The vma destruction code was using an unlocked advisory check for
+drm_mm_node_allocated() to avoid racing with eviction code unbinding
+the vma.
+
+This is very fragile and prohibits the dereference of non-refcounted
+pointers of dying vmas after a call to __i915_vma_unbind(). It also
+prohibits the dereference of vma->obj of refcounted pointers of
+dying vmas after a call to __i915_vma_unbind(), since even if a
+refcount is held on the vma, that won't guarantee that its backing
+object doesn't get destroyed.
+
+So introduce an unbind under the vm mutex at object destroy time,
+removing all weak references of the vma and its object from the
+object vma list and from the vm bound list.
+
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220127115622.302970-1-thomas.hellstrom@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/gem/i915_gem_object.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
+index 6fb9afb65034..5f48d5ea5c15 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
+@@ -224,6 +224,12 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj)
+                       GEM_BUG_ON(vma->obj != obj);
+                       spin_unlock(&obj->vma.lock);
++                      /* Verify that the vma is unbound under the vm mutex. */
++                      mutex_lock(&vma->vm->mutex);
++                      atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
++                      __i915_vma_unbind(vma);
++                      mutex_unlock(&vma->vm->mutex);
++
+                       __i915_vma_put(vma);
+                       spin_lock(&obj->vma.lock);
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-i915-gt-register-the-migrate-contexts-with-their.patch b/queue-5.15/drm-i915-gt-register-the-migrate-contexts-with-their.patch
new file mode 100644 (file)
index 0000000..fa4fbfe
--- /dev/null
@@ -0,0 +1,250 @@
+From ea74c0caed4a9be8b1480ab63c6f96e375c11ecf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Sep 2021 08:25:23 +0200
+Subject: drm/i915/gt: Register the migrate contexts with their engines
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit 3e42cc61275f95fd7f022b6380b95428efe134d3 ]
+
+Pinned contexts, like the migrate contexts need reset after resume
+since their context image may have been lost. Also the GuC needs to
+register pinned contexts.
+
+Add a list to struct intel_engine_cs where we add all pinned contexts on
+creation, and traverse that list at resume time to reset the pinned
+contexts.
+
+This fixes the kms_pipe_crc_basic@suspend-read-crc-pipe-a selftest for now,
+but proper LMEM backup / restore is needed for full suspend functionality.
+However, note that even with full LMEM backup / restore it may be
+desirable to keep the reset since backing up the migrate context images
+must happen using memcpy() after the migrate context has become inactive,
+and for performance- and other reasons we want to avoid memcpy() from
+LMEM.
+
+Also traverse the list at guc_init_lrc_mapping() calling
+guc_kernel_context_pin() for the pinned contexts, like is already done
+for the kernel context.
+
+v2:
+- Don't reset the contexts on each __engine_unpark() but rather at
+  resume time (Chris Wilson).
+v3:
+- Reset contexts in the engine sanitize callback. (Chris Wilson)
+
+Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
+Cc: Matthew Auld <matthew.auld@intel.com>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Brost Matthew <matthew.brost@intel.com>
+Cc: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Matthew Auld <matthew.auld@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-6-thomas.hellstrom@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/gt/intel_context_types.h |  8 +++++++
+ drivers/gpu/drm/i915/gt/intel_engine_cs.c     |  4 ++++
+ drivers/gpu/drm/i915/gt/intel_engine_pm.c     | 23 +++++++++++++++++++
+ drivers/gpu/drm/i915/gt/intel_engine_pm.h     |  2 ++
+ drivers/gpu/drm/i915/gt/intel_engine_types.h  |  7 ++++++
+ .../drm/i915/gt/intel_execlists_submission.c  |  2 ++
+ .../gpu/drm/i915/gt/intel_ring_submission.c   |  3 +++
+ drivers/gpu/drm/i915/gt/mock_engine.c         |  2 ++
+ .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 12 +++++++---
+ 9 files changed, 60 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
+index e54351a170e2..a63631ea0ec4 100644
+--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
++++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
+@@ -152,6 +152,14 @@ struct intel_context {
+       /** sseu: Control eu/slice partitioning */
+       struct intel_sseu sseu;
++      /**
++       * pinned_contexts_link: List link for the engine's pinned contexts.
++       * This is only used if this is a perma-pinned kernel context and
++       * the list is assumed to only be manipulated during driver load
++       * or unload time so no mutex protection currently.
++       */
++      struct list_head pinned_contexts_link;
++
+       u8 wa_bb_page; /* if set, page num reserved for context workarounds */
+       struct {
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+index 0d9105a31d84..eb99441e0ada 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+@@ -320,6 +320,7 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id)
+       BUILD_BUG_ON(BITS_PER_TYPE(engine->mask) < I915_NUM_ENGINES);
++      INIT_LIST_HEAD(&engine->pinned_contexts_list);
+       engine->id = id;
+       engine->legacy_idx = INVALID_ENGINE;
+       engine->mask = BIT(id);
+@@ -875,6 +876,8 @@ intel_engine_create_pinned_context(struct intel_engine_cs *engine,
+               return ERR_PTR(err);
+       }
++      list_add_tail(&ce->pinned_contexts_link, &engine->pinned_contexts_list);
++
+       /*
+        * Give our perma-pinned kernel timelines a separate lockdep class,
+        * so that we can use them from within the normal user timelines
+@@ -897,6 +900,7 @@ void intel_engine_destroy_pinned_context(struct intel_context *ce)
+       list_del(&ce->timeline->engine_link);
+       mutex_unlock(&hwsp->vm->mutex);
++      list_del(&ce->pinned_contexts_link);
+       intel_context_unpin(ce);
+       intel_context_put(ce);
+ }
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+index 1f07ac4e0672..dacd62773735 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+@@ -298,6 +298,29 @@ void intel_engine_init__pm(struct intel_engine_cs *engine)
+       intel_engine_init_heartbeat(engine);
+ }
++/**
++ * intel_engine_reset_pinned_contexts - Reset the pinned contexts of
++ * an engine.
++ * @engine: The engine whose pinned contexts we want to reset.
++ *
++ * Typically the pinned context LMEM images lose or get their content
++ * corrupted on suspend. This function resets their images.
++ */
++void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine)
++{
++      struct intel_context *ce;
++
++      list_for_each_entry(ce, &engine->pinned_contexts_list,
++                          pinned_contexts_link) {
++              /* kernel context gets reset at __engine_unpark() */
++              if (ce == engine->kernel_context)
++                      continue;
++
++              dbg_poison_ce(ce);
++              ce->ops->reset(ce);
++      }
++}
++
+ #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+ #include "selftest_engine_pm.c"
+ #endif
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
+index 70ea46d6cfb0..8520c595f5e1 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h
++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
+@@ -69,4 +69,6 @@ intel_engine_create_kernel_request(struct intel_engine_cs *engine)
+ void intel_engine_init__pm(struct intel_engine_cs *engine);
++void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine);
++
+ #endif /* INTEL_ENGINE_PM_H */
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
+index ed91bcff20eb..adc44c9fac6d 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
++++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
+@@ -304,6 +304,13 @@ struct intel_engine_cs {
+       struct intel_context *kernel_context; /* pinned */
++      /**
++       * pinned_contexts_list: List of pinned contexts. This list is only
++       * assumed to be manipulated during driver load- or unload time and
++       * does therefore not have any additional protection.
++       */
++      struct list_head pinned_contexts_list;
++
+       intel_engine_mask_t saturated; /* submitting semaphores too late? */
+       struct {
+diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+index cafb0608ffb4..416f5e0657f0 100644
+--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+@@ -2787,6 +2787,8 @@ static void execlists_sanitize(struct intel_engine_cs *engine)
+       /* And scrub the dirty cachelines for the HWSP */
+       clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++
++      intel_engine_reset_pinned_contexts(engine);
+ }
+ static void enable_error_interrupt(struct intel_engine_cs *engine)
+diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+index 2958e2fae380..6f2f6ba87397 100644
+--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+@@ -17,6 +17,7 @@
+ #include "intel_ring.h"
+ #include "shmem_utils.h"
+ #include "intel_engine_heartbeat.h"
++#include "intel_engine_pm.h"
+ /* Rough estimate of the typical request size, performing a flush,
+  * set-context and then emitting the batch.
+@@ -292,6 +293,8 @@ static void xcs_sanitize(struct intel_engine_cs *engine)
+       /* And scrub the dirty cachelines for the HWSP */
+       clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++
++      intel_engine_reset_pinned_contexts(engine);
+ }
+ static void reset_prepare(struct intel_engine_cs *engine)
+diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c
+index 2c1af030310c..8b89215afe46 100644
+--- a/drivers/gpu/drm/i915/gt/mock_engine.c
++++ b/drivers/gpu/drm/i915/gt/mock_engine.c
+@@ -376,6 +376,8 @@ int mock_engine_init(struct intel_engine_cs *engine)
+ {
+       struct intel_context *ce;
++      INIT_LIST_HEAD(&engine->pinned_contexts_list);
++
+       engine->sched_engine = i915_sched_engine_create(ENGINE_MOCK);
+       if (!engine->sched_engine)
+               return -ENOMEM;
+diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+index 93c9de8f43e8..6e09a1cca37b 100644
+--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+@@ -2347,6 +2347,8 @@ static void guc_sanitize(struct intel_engine_cs *engine)
+       /* And scrub the dirty cachelines for the HWSP */
+       clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++
++      intel_engine_reset_pinned_contexts(engine);
+ }
+ static void setup_hwsp(struct intel_engine_cs *engine)
+@@ -2422,9 +2424,13 @@ static inline void guc_init_lrc_mapping(struct intel_guc *guc)
+        * and even it did this code would be run again.
+        */
+-      for_each_engine(engine, gt, id)
+-              if (engine->kernel_context)
+-                      guc_kernel_context_pin(guc, engine->kernel_context);
++      for_each_engine(engine, gt, id) {
++              struct intel_context *ce;
++
++              list_for_each_entry(ce, &engine->pinned_contexts_list,
++                                  pinned_contexts_link)
++                      guc_kernel_context_pin(guc, ce);
++      }
+ }
+ static void guc_release(struct intel_engine_cs *engine)
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-i915-replace-the-unconditional-clflush-with-drm_.patch b/queue-5.15/drm-i915-replace-the-unconditional-clflush-with-drm_.patch
new file mode 100644 (file)
index 0000000..4f98355
--- /dev/null
@@ -0,0 +1,50 @@
+From 2ffa1c26e9b351e188d9dc2dbd2805b403ca69ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Oct 2021 12:09:38 +0300
+Subject: drm/i915: Replace the unconditional clflush with
+ drm_clflush_virt_range()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ville Syrjälä <ville.syrjala@linux.intel.com>
+
+[ Upstream commit ef7ec41f17cbc0861891ccc0634d06a0c8dcbf09 ]
+
+Not all machines have clflush, so don't go assuming they do.
+Not really sure why the clflush is even here since hwsp
+is supposed to get snooped I thought.
+
+Although in my case we're talking about a i830 machine where
+render/blitter snooping is definitely busted. But it might
+work for the hswp perhaps. Haven't really reverse engineered
+that one fully.
+
+Cc: stable@vger.kernel.org
+Cc: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
+Fixes: b436a5f8b6c8 ("drm/i915/gt: Track all timelines created using the HWSP")
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20211014090941.12159-2-ville.syrjala@linux.intel.com
+Reviewed-by: Dave Airlie <airlied@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/gt/intel_ring_submission.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+index 6f2f6ba87397..02e18e70c78e 100644
+--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+@@ -292,7 +292,7 @@ static void xcs_sanitize(struct intel_engine_cs *engine)
+       sanitize_hwsp(engine);
+       /* And scrub the dirty cachelines for the HWSP */
+-      clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++      drm_clflush_virt_range(engine->status_page.addr, PAGE_SIZE);
+       intel_engine_reset_pinned_contexts(engine);
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch b/queue-5.15/drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch
new file mode 100644 (file)
index 0000000..7f166b8
--- /dev/null
@@ -0,0 +1,140 @@
+From c29768e62291d544a0a5302b93ff7327f4c21fa3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Oct 2021 18:19:10 +0800
+Subject: drm/mediatek: Add cmdq_handle in mtk_crtc
+
+From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+
+[ Upstream commit 7627122fd1c06800a1fe624e9fb3c269796115e8 ]
+
+One mtk_crtc need just one cmdq_handle, so add one cmdq_handle
+in mtk_crtc to prevent frequently allocation and free of
+cmdq_handle.
+
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: jason-jh.lin <jason-jh.lin@mediatek.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 62 +++++++++++++++++++++++--
+ 1 file changed, 57 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+index dad1f85ee315..ffa54b416ca7 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+@@ -53,6 +53,7 @@ struct mtk_drm_crtc {
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       struct cmdq_client              cmdq_client;
++      struct cmdq_pkt                 cmdq_handle;
+       u32                             cmdq_event;
+       u32                             cmdq_vblank_cnt;
+ #endif
+@@ -107,12 +108,55 @@ static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
+       }
+ }
++#if IS_REACHABLE(CONFIG_MTK_CMDQ)
++static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
++                                 size_t size)
++{
++      struct device *dev;
++      dma_addr_t dma_addr;
++
++      pkt->va_base = kzalloc(size, GFP_KERNEL);
++      if (!pkt->va_base) {
++              kfree(pkt);
++              return -ENOMEM;
++      }
++      pkt->buf_size = size;
++      pkt->cl = (void *)client;
++
++      dev = client->chan->mbox->dev;
++      dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
++                                DMA_TO_DEVICE);
++      if (dma_mapping_error(dev, dma_addr)) {
++              dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
++              kfree(pkt->va_base);
++              kfree(pkt);
++              return -ENOMEM;
++      }
++
++      pkt->pa_base = dma_addr;
++
++      return 0;
++}
++
++static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
++{
++      struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
++
++      dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
++                       DMA_TO_DEVICE);
++      kfree(pkt->va_base);
++      kfree(pkt);
++}
++#endif
++
+ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
+ {
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+       mtk_mutex_put(mtk_crtc->mutex);
+-
++#if IS_REACHABLE(CONFIG_MTK_CMDQ)
++      mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle);
++#endif
+       drm_crtc_cleanup(crtc);
+ }
+@@ -227,12 +271,10 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc,
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
+ {
+-      struct cmdq_cb_data *data = mssg;
+       struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client);
+       struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client);
+       mtk_crtc->cmdq_vblank_cnt = 0;
+-      cmdq_pkt_destroy(data->pkt);
+ }
+ #endif
+@@ -438,7 +480,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+                                      bool needs_vblank)
+ {
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-      struct cmdq_pkt *cmdq_handle;
++      struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle;
+ #endif
+       struct drm_crtc *crtc = &mtk_crtc->base;
+       struct mtk_drm_private *priv = crtc->dev->dev_private;
+@@ -478,7 +520,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       if (mtk_crtc->cmdq_client.chan) {
+               mbox_flush(mtk_crtc->cmdq_client.chan, 2000);
+-              cmdq_handle = cmdq_pkt_create(&mtk_crtc->cmdq_client, PAGE_SIZE);
++              cmdq_handle->cmd_buf_size = 0;
+               cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
+               cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
+               mtk_crtc_ddp_config(crtc, cmdq_handle);
+@@ -877,6 +919,16 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+                               drm_crtc_index(&mtk_crtc->base));
+                       mbox_free_channel(mtk_crtc->cmdq_client.chan);
+                       mtk_crtc->cmdq_client.chan = NULL;
++              } else {
++                      ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client,
++                                                    &mtk_crtc->cmdq_handle,
++                                                    PAGE_SIZE);
++                      if (ret) {
++                              dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n",
++                                      drm_crtc_index(&mtk_crtc->base));
++                              mbox_free_channel(mtk_crtc->cmdq_client.chan);
++                              mtk_crtc->cmdq_client.chan = NULL;
++                      }
+               }
+       }
+ #endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-mediatek-add-vblank-register-unregister-callback.patch b/queue-5.15/drm-mediatek-add-vblank-register-unregister-callback.patch
new file mode 100644 (file)
index 0000000..07b4d0a
--- /dev/null
@@ -0,0 +1,275 @@
+From ccb25dd2f399e9ece9cbe5d484777ce1b585caa2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Mar 2022 15:23:20 +0800
+Subject: drm/mediatek: Add vblank register/unregister callback functions
+
+From: Rex-BC Chen <rex-bc.chen@mediatek.com>
+
+[ Upstream commit b74d921b900b6ce38c6247c0a1c86be9f3746493 ]
+
+We encountered a kernel panic issue that callback data will be NULL when
+it's using in ovl irq handler. There is a timing issue between
+mtk_disp_ovl_irq_handler() and mtk_ovl_disable_vblank().
+
+To resolve this issue, we use the flow to register/unregister vblank cb:
+- Register callback function and callback data when crtc creates.
+- Unregister callback function and callback data when crtc destroies.
+
+With this solution, we can assure callback data will not be NULL when
+vblank is disable.
+
+Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20220321072320.15019-1-rex-bc.chen@mediatek.com/
+Fixes: 9b0704988b15 ("drm/mediatek: Register vblank callback function")
+Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
+Reviewed-by: jason-jh.lin <jason-jh.lin@mediatek.com>
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_disp_drv.h     | 16 +++++++-----
+ drivers/gpu/drm/mediatek/mtk_disp_ovl.c     | 22 ++++++++++++----
+ drivers/gpu/drm/mediatek/mtk_disp_rdma.c    | 20 +++++++++-----
+ drivers/gpu/drm/mediatek/mtk_drm_crtc.c     | 14 +++++++++-
+ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  4 +++
+ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 29 ++++++++++++++++-----
+ 6 files changed, 80 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+index 86c3068894b1..974462831133 100644
+--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
++++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+@@ -76,9 +76,11 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
+ void mtk_ovl_start(struct device *dev);
+ void mtk_ovl_stop(struct device *dev);
+ unsigned int mtk_ovl_supported_rotations(struct device *dev);
+-void mtk_ovl_enable_vblank(struct device *dev,
+-                         void (*vblank_cb)(void *),
+-                         void *vblank_cb_data);
++void mtk_ovl_register_vblank_cb(struct device *dev,
++                              void (*vblank_cb)(void *),
++                              void *vblank_cb_data);
++void mtk_ovl_unregister_vblank_cb(struct device *dev);
++void mtk_ovl_enable_vblank(struct device *dev);
+ void mtk_ovl_disable_vblank(struct device *dev);
+ void mtk_rdma_bypass_shadow(struct device *dev);
+@@ -93,9 +95,11 @@ void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
+                          struct cmdq_pkt *cmdq_pkt);
+ void mtk_rdma_start(struct device *dev);
+ void mtk_rdma_stop(struct device *dev);
+-void mtk_rdma_enable_vblank(struct device *dev,
+-                          void (*vblank_cb)(void *),
+-                          void *vblank_cb_data);
++void mtk_rdma_register_vblank_cb(struct device *dev,
++                               void (*vblank_cb)(void *),
++                               void *vblank_cb_data);
++void mtk_rdma_unregister_vblank_cb(struct device *dev);
++void mtk_rdma_enable_vblank(struct device *dev);
+ void mtk_rdma_disable_vblank(struct device *dev);
+ #endif
+diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+index 5326989d5206..411cf0f21661 100644
+--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
++++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+@@ -96,14 +96,28 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
+       return IRQ_HANDLED;
+ }
+-void mtk_ovl_enable_vblank(struct device *dev,
+-                         void (*vblank_cb)(void *),
+-                         void *vblank_cb_data)
++void mtk_ovl_register_vblank_cb(struct device *dev,
++                              void (*vblank_cb)(void *),
++                              void *vblank_cb_data)
+ {
+       struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+       ovl->vblank_cb = vblank_cb;
+       ovl->vblank_cb_data = vblank_cb_data;
++}
++
++void mtk_ovl_unregister_vblank_cb(struct device *dev)
++{
++      struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
++
++      ovl->vblank_cb = NULL;
++      ovl->vblank_cb_data = NULL;
++}
++
++void mtk_ovl_enable_vblank(struct device *dev)
++{
++      struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
++
+       writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
+       writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN);
+ }
+@@ -112,8 +126,6 @@ void mtk_ovl_disable_vblank(struct device *dev)
+ {
+       struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+-      ovl->vblank_cb = NULL;
+-      ovl->vblank_cb_data = NULL;
+       writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
+ }
+diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+index 75d7f45579e2..a6a6cb5f75af 100644
+--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
++++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+@@ -94,24 +94,32 @@ static void rdma_update_bits(struct device *dev, unsigned int reg,
+       writel(tmp, rdma->regs + reg);
+ }
+-void mtk_rdma_enable_vblank(struct device *dev,
+-                          void (*vblank_cb)(void *),
+-                          void *vblank_cb_data)
++void mtk_rdma_register_vblank_cb(struct device *dev,
++                               void (*vblank_cb)(void *),
++                               void *vblank_cb_data)
+ {
+       struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+       rdma->vblank_cb = vblank_cb;
+       rdma->vblank_cb_data = vblank_cb_data;
+-      rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
+-                       RDMA_FRAME_END_INT);
+ }
+-void mtk_rdma_disable_vblank(struct device *dev)
++void mtk_rdma_unregister_vblank_cb(struct device *dev)
+ {
+       struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+       rdma->vblank_cb = NULL;
+       rdma->vblank_cb_data = NULL;
++}
++
++void mtk_rdma_enable_vblank(struct device *dev)
++{
++      rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
++                       RDMA_FRAME_END_INT);
++}
++
++void mtk_rdma_disable_vblank(struct device *dev)
++{
+       rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
+ }
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+index ffa54b416ca7..34bb6c713a90 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+@@ -152,11 +152,20 @@ static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
+ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
+ {
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
++      int i;
+       mtk_mutex_put(mtk_crtc->mutex);
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle);
+ #endif
++
++      for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
++              struct mtk_ddp_comp *comp;
++
++              comp = mtk_crtc->ddp_comp[i];
++              mtk_ddp_comp_unregister_vblank_cb(comp);
++      }
++
+       drm_crtc_cleanup(crtc);
+ }
+@@ -570,7 +579,7 @@ static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc)
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+       struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+-      mtk_ddp_comp_enable_vblank(comp, mtk_crtc_ddp_irq, &mtk_crtc->base);
++      mtk_ddp_comp_enable_vblank(comp);
+       return 0;
+ }
+@@ -870,6 +879,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+                       if (comp->funcs->ctm_set)
+                               has_ctm = true;
+               }
++
++              mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
++                                              &mtk_crtc->base);
+       }
+       for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+index 99cbf44463e4..22d23668b484 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+@@ -276,6 +276,8 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
+       .config = mtk_ovl_config,
+       .start = mtk_ovl_start,
+       .stop = mtk_ovl_stop,
++      .register_vblank_cb = mtk_ovl_register_vblank_cb,
++      .unregister_vblank_cb = mtk_ovl_unregister_vblank_cb,
+       .enable_vblank = mtk_ovl_enable_vblank,
+       .disable_vblank = mtk_ovl_disable_vblank,
+       .supported_rotations = mtk_ovl_supported_rotations,
+@@ -292,6 +294,8 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
+       .config = mtk_rdma_config,
+       .start = mtk_rdma_start,
+       .stop = mtk_rdma_stop,
++      .register_vblank_cb = mtk_rdma_register_vblank_cb,
++      .unregister_vblank_cb = mtk_rdma_unregister_vblank_cb,
+       .enable_vblank = mtk_rdma_enable_vblank,
+       .disable_vblank = mtk_rdma_disable_vblank,
+       .layer_nr = mtk_rdma_layer_nr,
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+index bb914d976cf5..25cb50f2391f 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+@@ -47,9 +47,11 @@ struct mtk_ddp_comp_funcs {
+                      unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+       void (*start)(struct device *dev);
+       void (*stop)(struct device *dev);
+-      void (*enable_vblank)(struct device *dev,
+-                            void (*vblank_cb)(void *),
+-                            void *vblank_cb_data);
++      void (*register_vblank_cb)(struct device *dev,
++                                 void (*vblank_cb)(void *),
++                                 void *vblank_cb_data);
++      void (*unregister_vblank_cb)(struct device *dev);
++      void (*enable_vblank)(struct device *dev);
+       void (*disable_vblank)(struct device *dev);
+       unsigned int (*supported_rotations)(struct device *dev);
+       unsigned int (*layer_nr)(struct device *dev);
+@@ -110,12 +112,25 @@ static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp)
+               comp->funcs->stop(comp->dev);
+ }
+-static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp,
+-                                            void (*vblank_cb)(void *),
+-                                            void *vblank_cb_data)
++static inline void mtk_ddp_comp_register_vblank_cb(struct mtk_ddp_comp *comp,
++                                                 void (*vblank_cb)(void *),
++                                                 void *vblank_cb_data)
++{
++      if (comp->funcs && comp->funcs->register_vblank_cb)
++              comp->funcs->register_vblank_cb(comp->dev, vblank_cb,
++                                              vblank_cb_data);
++}
++
++static inline void mtk_ddp_comp_unregister_vblank_cb(struct mtk_ddp_comp *comp)
++{
++      if (comp->funcs && comp->funcs->unregister_vblank_cb)
++              comp->funcs->unregister_vblank_cb(comp->dev);
++}
++
++static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp)
+ {
+       if (comp->funcs && comp->funcs->enable_vblank)
+-              comp->funcs->enable_vblank(comp->dev, vblank_cb, vblank_cb_data);
++              comp->funcs->enable_vblank(comp->dev);
+ }
+ static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp)
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-mediatek-detect-cmdq-execution-timeout.patch b/queue-5.15/drm-mediatek-detect-cmdq-execution-timeout.patch
new file mode 100644 (file)
index 0000000..d38d408
--- /dev/null
@@ -0,0 +1,81 @@
+From e00118f8bbf5550fc398d49351084f1d9cd2726b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Oct 2021 10:18:54 +0800
+Subject: drm/mediatek: Detect CMDQ execution timeout
+
+From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+
+[ Upstream commit eaf80126aba6fd1754837eec91e4c8bbd58ae52e ]
+
+CMDQ is used to update display register in vblank period, so
+it should be execute in next 2 vblank. One vblank interrupt
+before send message (occasionally) and one vblank interrupt
+after cmdq done. If it fail to execute in next 3 vblank,
+tiemout happen.
+
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: jason-jh.lin <jason-jh.lin@mediatek.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+index e23e3224ac67..dad1f85ee315 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+@@ -54,6 +54,7 @@ struct mtk_drm_crtc {
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       struct cmdq_client              cmdq_client;
+       u32                             cmdq_event;
++      u32                             cmdq_vblank_cnt;
+ #endif
+       struct device                   *mmsys_dev;
+@@ -227,7 +228,10 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc,
+ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
+ {
+       struct cmdq_cb_data *data = mssg;
++      struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client);
++      struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client);
++      mtk_crtc->cmdq_vblank_cnt = 0;
+       cmdq_pkt_destroy(data->pkt);
+ }
+ #endif
+@@ -483,6 +487,15 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+                                          cmdq_handle->pa_base,
+                                          cmdq_handle->cmd_buf_size,
+                                          DMA_TO_DEVICE);
++              /*
++               * CMDQ command should execute in next 3 vblank.
++               * One vblank interrupt before send message (occasionally)
++               * and one vblank interrupt after cmdq done,
++               * so it's timeout after 3 vblank interrupt.
++               * If it fail to execute in next 3 vblank, timeout happen.
++               */
++              mtk_crtc->cmdq_vblank_cnt = 3;
++
+               mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle);
+               mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0);
+       }
+@@ -499,11 +512,14 @@ static void mtk_crtc_ddp_irq(void *data)
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
++              mtk_crtc_ddp_config(crtc, NULL);
++      else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0)
++              DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n",
++                        drm_crtc_index(&mtk_crtc->base));
+ #else
+       if (!priv->data->shadow_register)
+-#endif
+               mtk_crtc_ddp_config(crtc, NULL);
+-
++#endif
+       mtk_drm_finish_page_flip(mtk_crtc);
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch b/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch
new file mode 100644 (file)
index 0000000..1ac1006
--- /dev/null
@@ -0,0 +1,268 @@
+From 70db39b21100039062b6e3703491a3fb9c0bb3e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 31 Jan 2022 09:55:20 +0100
+Subject: drm/mediatek: mtk_dsi: Avoid EPROBE_DEFER loop with external bridge
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+[ Upstream commit 647474b8d980256b26b1cd112d7333a4dbd4260a ]
+
+DRM bridge drivers are now attaching their DSI device at probe time,
+which requires us to register our DSI host in order to let the bridge
+to probe: this recently started producing an endless -EPROBE_DEFER
+loop on some machines that are using external bridges, like the
+parade-ps8640, found on the ACER Chromebook R13.
+
+Now that the DSI hosts/devices probe sequence is documented, we can
+do adjustments to the mtk_dsi driver as to both fix now and make sure
+to avoid this situation in the future: for this, following what is
+documented in drm_bridge.c, move the mtk_dsi component_add() to the
+mtk_dsi_ops.attach callback and delete it in the detach callback;
+keeping in mind that we are registering a drm_bridge for our DSI,
+which is only used/attached if the DSI Host is bound, it wouldn't
+make sense to keep adding our bridge at probe time (as it would
+be useless to have it if mtk_dsi_ops.attach() fails!), so also move
+that one to the dsi host attach function (and remove it in detach).
+
+Cc: <stable@vger.kernel.org> # 5.15.x
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Reviewed-by: Andrzej Hajda <andrzej.hajda@intel.com>
+Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
+Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_dsi.c | 167 +++++++++++++++--------------
+ 1 file changed, 84 insertions(+), 83 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
+index 5d90d2eb0019..bced4c7d668e 100644
+--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
+@@ -786,18 +786,101 @@ void mtk_dsi_ddp_stop(struct device *dev)
+       mtk_dsi_poweroff(dsi);
+ }
++static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
++{
++      int ret;
++
++      ret = drm_simple_encoder_init(drm, &dsi->encoder,
++                                    DRM_MODE_ENCODER_DSI);
++      if (ret) {
++              DRM_ERROR("Failed to encoder init to drm\n");
++              return ret;
++      }
++
++      dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
++
++      ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
++                              DRM_BRIDGE_ATTACH_NO_CONNECTOR);
++      if (ret)
++              goto err_cleanup_encoder;
++
++      dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
++      if (IS_ERR(dsi->connector)) {
++              DRM_ERROR("Unable to create bridge connector\n");
++              ret = PTR_ERR(dsi->connector);
++              goto err_cleanup_encoder;
++      }
++      drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
++
++      return 0;
++
++err_cleanup_encoder:
++      drm_encoder_cleanup(&dsi->encoder);
++      return ret;
++}
++
++static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
++{
++      int ret;
++      struct drm_device *drm = data;
++      struct mtk_dsi *dsi = dev_get_drvdata(dev);
++
++      ret = mtk_dsi_encoder_init(drm, dsi);
++      if (ret)
++              return ret;
++
++      return device_reset_optional(dev);
++}
++
++static void mtk_dsi_unbind(struct device *dev, struct device *master,
++                         void *data)
++{
++      struct mtk_dsi *dsi = dev_get_drvdata(dev);
++
++      drm_encoder_cleanup(&dsi->encoder);
++}
++
++static const struct component_ops mtk_dsi_component_ops = {
++      .bind = mtk_dsi_bind,
++      .unbind = mtk_dsi_unbind,
++};
++
+ static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
+                              struct mipi_dsi_device *device)
+ {
+       struct mtk_dsi *dsi = host_to_dsi(host);
++      struct device *dev = host->dev;
++      int ret;
+       dsi->lanes = device->lanes;
+       dsi->format = device->format;
+       dsi->mode_flags = device->mode_flags;
++      dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
++      if (IS_ERR(dsi->next_bridge))
++              return PTR_ERR(dsi->next_bridge);
++
++      drm_bridge_add(&dsi->bridge);
++
++      ret = component_add(host->dev, &mtk_dsi_component_ops);
++      if (ret) {
++              DRM_ERROR("failed to add dsi_host component: %d\n", ret);
++              drm_bridge_remove(&dsi->bridge);
++              return ret;
++      }
+       return 0;
+ }
++static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
++                             struct mipi_dsi_device *device)
++{
++      struct mtk_dsi *dsi = host_to_dsi(host);
++
++      component_del(host->dev, &mtk_dsi_component_ops);
++      drm_bridge_remove(&dsi->bridge);
++      return 0;
++}
++
+ static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
+ {
+       int ret;
+@@ -938,73 +1021,14 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
+ static const struct mipi_dsi_host_ops mtk_dsi_ops = {
+       .attach = mtk_dsi_host_attach,
++      .detach = mtk_dsi_host_detach,
+       .transfer = mtk_dsi_host_transfer,
+ };
+-static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
+-{
+-      int ret;
+-
+-      ret = drm_simple_encoder_init(drm, &dsi->encoder,
+-                                    DRM_MODE_ENCODER_DSI);
+-      if (ret) {
+-              DRM_ERROR("Failed to encoder init to drm\n");
+-              return ret;
+-      }
+-
+-      dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
+-
+-      ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
+-                              DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+-      if (ret)
+-              goto err_cleanup_encoder;
+-
+-      dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
+-      if (IS_ERR(dsi->connector)) {
+-              DRM_ERROR("Unable to create bridge connector\n");
+-              ret = PTR_ERR(dsi->connector);
+-              goto err_cleanup_encoder;
+-      }
+-      drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
+-
+-      return 0;
+-
+-err_cleanup_encoder:
+-      drm_encoder_cleanup(&dsi->encoder);
+-      return ret;
+-}
+-
+-static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
+-{
+-      int ret;
+-      struct drm_device *drm = data;
+-      struct mtk_dsi *dsi = dev_get_drvdata(dev);
+-
+-      ret = mtk_dsi_encoder_init(drm, dsi);
+-      if (ret)
+-              return ret;
+-
+-      return device_reset_optional(dev);
+-}
+-
+-static void mtk_dsi_unbind(struct device *dev, struct device *master,
+-                         void *data)
+-{
+-      struct mtk_dsi *dsi = dev_get_drvdata(dev);
+-
+-      drm_encoder_cleanup(&dsi->encoder);
+-}
+-
+-static const struct component_ops mtk_dsi_component_ops = {
+-      .bind = mtk_dsi_bind,
+-      .unbind = mtk_dsi_unbind,
+-};
+-
+ static int mtk_dsi_probe(struct platform_device *pdev)
+ {
+       struct mtk_dsi *dsi;
+       struct device *dev = &pdev->dev;
+-      struct drm_panel *panel;
+       struct resource *regs;
+       int irq_num;
+       int ret;
+@@ -1021,19 +1045,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
+               return ret;
+       }
+-      ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+-                                        &panel, &dsi->next_bridge);
+-      if (ret)
+-              goto err_unregister_host;
+-
+-      if (panel) {
+-              dsi->next_bridge = devm_drm_panel_bridge_add(dev, panel);
+-              if (IS_ERR(dsi->next_bridge)) {
+-                      ret = PTR_ERR(dsi->next_bridge);
+-                      goto err_unregister_host;
+-              }
+-      }
+-
+       dsi->driver_data = of_device_get_match_data(dev);
+       dsi->engine_clk = devm_clk_get(dev, "engine");
+@@ -1098,14 +1109,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
+       dsi->bridge.of_node = dev->of_node;
+       dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+-      drm_bridge_add(&dsi->bridge);
+-
+-      ret = component_add(&pdev->dev, &mtk_dsi_component_ops);
+-      if (ret) {
+-              dev_err(&pdev->dev, "failed to add component: %d\n", ret);
+-              goto err_unregister_host;
+-      }
+-
+       return 0;
+ err_unregister_host:
+@@ -1118,8 +1121,6 @@ static int mtk_dsi_remove(struct platform_device *pdev)
+       struct mtk_dsi *dsi = platform_get_drvdata(pdev);
+       mtk_output_dsi_disable(dsi);
+-      drm_bridge_remove(&dsi->bridge);
+-      component_del(&pdev->dev, &mtk_dsi_component_ops);
+       mipi_dsi_host_unregister(&dsi->host);
+       return 0;
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch b/queue-5.15/drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch
new file mode 100644 (file)
index 0000000..8f3704d
--- /dev/null
@@ -0,0 +1,131 @@
+From 1c9bd99353e173a96fd2eb4f3ffd9516ba08add5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Oct 2021 18:19:08 +0800
+Subject: drm/mediatek: Remove the pointer of struct cmdq_client
+
+From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+
+[ Upstream commit 563c9d4a5b117552150efbecbaf0877947e98a32 ]
+
+In mailbox rx_callback, it pass struct mbox_client to callback
+function, but it could not map back to mtk_drm_crtc instance
+because struct cmdq_client use a pointer to struct mbox_client:
+
+struct cmdq_client {
+       struct mbox_client client;
+       struct mbox_chan *chan;
+};
+
+struct mtk_drm_crtc {
+       /* client instance data */
+       struct cmdq_client *cmdq_client;
+};
+
+so remove the pointer of struct cmdq_client and let mtk_drm_crtc
+instance define cmdq_client as:
+
+struct mtk_drm_crtc {
+       /* client instance data */
+       struct cmdq_client cmdq_client;
+};
+
+and in rx_callback function, use struct mbox_client to get
+struct mtk_drm_crtc.
+
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: jason-jh.lin <jason-jh.lin@mediatek.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 37 +++++++++++++------------
+ 1 file changed, 20 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+index 369d3e68c0b6..e23e3224ac67 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+@@ -52,7 +52,7 @@ struct mtk_drm_crtc {
+       bool                            pending_async_planes;
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-      struct cmdq_client              *cmdq_client;
++      struct cmdq_client              cmdq_client;
+       u32                             cmdq_event;
+ #endif
+@@ -472,19 +472,19 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+               mtk_mutex_release(mtk_crtc->mutex);
+       }
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-      if (mtk_crtc->cmdq_client) {
+-              mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
+-              cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
++      if (mtk_crtc->cmdq_client.chan) {
++              mbox_flush(mtk_crtc->cmdq_client.chan, 2000);
++              cmdq_handle = cmdq_pkt_create(&mtk_crtc->cmdq_client, PAGE_SIZE);
+               cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
+               cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
+               mtk_crtc_ddp_config(crtc, cmdq_handle);
+               cmdq_pkt_finalize(cmdq_handle);
+-              dma_sync_single_for_device(mtk_crtc->cmdq_client->chan->mbox->dev,
++              dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev,
+                                          cmdq_handle->pa_base,
+                                          cmdq_handle->cmd_buf_size,
+                                          DMA_TO_DEVICE);
+-              mbox_send_message(mtk_crtc->cmdq_client->chan, cmdq_handle);
+-              mbox_client_txdone(mtk_crtc->cmdq_client->chan, 0);
++              mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle);
++              mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0);
+       }
+ #endif
+       mtk_crtc->config_updating = false;
+@@ -498,7 +498,7 @@ static void mtk_crtc_ddp_irq(void *data)
+       struct mtk_drm_private *priv = crtc->dev->dev_private;
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-      if (!priv->data->shadow_register && !mtk_crtc->cmdq_client)
++      if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
+ #else
+       if (!priv->data->shadow_register)
+ #endif
+@@ -838,17 +838,20 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+       mutex_init(&mtk_crtc->hw_lock);
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-      mtk_crtc->cmdq_client =
+-                      cmdq_mbox_create(mtk_crtc->mmsys_dev,
+-                                       drm_crtc_index(&mtk_crtc->base));
+-      if (IS_ERR(mtk_crtc->cmdq_client)) {
++      mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev;
++      mtk_crtc->cmdq_client.client.tx_block = false;
++      mtk_crtc->cmdq_client.client.knows_txdone = true;
++      mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb;
++      mtk_crtc->cmdq_client.chan =
++                      mbox_request_channel(&mtk_crtc->cmdq_client.client,
++                                           drm_crtc_index(&mtk_crtc->base));
++      if (IS_ERR(mtk_crtc->cmdq_client.chan)) {
+               dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n",
+                       drm_crtc_index(&mtk_crtc->base));
+-              mtk_crtc->cmdq_client = NULL;
++              mtk_crtc->cmdq_client.chan = NULL;
+       }
+-      if (mtk_crtc->cmdq_client) {
+-              mtk_crtc->cmdq_client->client.rx_callback = ddp_cmdq_cb;
++      if (mtk_crtc->cmdq_client.chan) {
+               ret = of_property_read_u32_index(priv->mutex_node,
+                                                "mediatek,gce-events",
+                                                drm_crtc_index(&mtk_crtc->base),
+@@ -856,8 +859,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+               if (ret) {
+                       dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",
+                               drm_crtc_index(&mtk_crtc->base));
+-                      cmdq_mbox_destroy(mtk_crtc->cmdq_client);
+-                      mtk_crtc->cmdq_client = NULL;
++                      mbox_free_channel(mtk_crtc->cmdq_client.chan);
++                      mtk_crtc->cmdq_client.chan = NULL;
+               }
+       }
+ #endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch b/queue-5.15/drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch
new file mode 100644 (file)
index 0000000..cbaaec5
--- /dev/null
@@ -0,0 +1,72 @@
+From 84e5124774632183df77a9afcf853ce807b60f60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Oct 2021 18:19:07 +0800
+Subject: drm/mediatek: Use mailbox rx_callback instead of cmdq_task_cb
+
+From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+
+[ Upstream commit 1ee07a683b7e4e6ad9ad4f77fce4751741bc8ceb ]
+
+rx_callback is a standard mailbox callback mechanism and could cover the
+function of proprietary cmdq_task_cb, so use the standard one instead of
+the proprietary one.
+
+Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
+Signed-off-by: jason-jh.lin <jason-jh.lin@mediatek.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+index a4e80e499674..369d3e68c0b6 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+@@ -4,6 +4,8 @@
+  */
+ #include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/mailbox_controller.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/soc/mediatek/mtk-cmdq.h>
+ #include <linux/soc/mediatek/mtk-mmsys.h>
+@@ -222,9 +224,11 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc,
+ }
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-static void ddp_cmdq_cb(struct cmdq_cb_data data)
++static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
+ {
+-      cmdq_pkt_destroy(data.data);
++      struct cmdq_cb_data *data = mssg;
++
++      cmdq_pkt_destroy(data->pkt);
+ }
+ #endif
+@@ -475,7 +479,12 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+               cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
+               mtk_crtc_ddp_config(crtc, cmdq_handle);
+               cmdq_pkt_finalize(cmdq_handle);
+-              cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);
++              dma_sync_single_for_device(mtk_crtc->cmdq_client->chan->mbox->dev,
++                                         cmdq_handle->pa_base,
++                                         cmdq_handle->cmd_buf_size,
++                                         DMA_TO_DEVICE);
++              mbox_send_message(mtk_crtc->cmdq_client->chan, cmdq_handle);
++              mbox_client_txdone(mtk_crtc->cmdq_client->chan, 0);
+       }
+ #endif
+       mtk_crtc->config_updating = false;
+@@ -839,6 +848,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+       }
+       if (mtk_crtc->cmdq_client) {
++              mtk_crtc->cmdq_client->client.rx_callback = ddp_cmdq_cb;
+               ret = of_property_read_u32_index(priv->mutex_node,
+                                                "mediatek,gce-events",
+                                                drm_crtc_index(&mtk_crtc->base),
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch b/queue-5.15/drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch
new file mode 100644 (file)
index 0000000..fc6ba93
--- /dev/null
@@ -0,0 +1,270 @@
+From 41d3abef580d693a38c7b7c5b130fa7412d97f86 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Dec 2021 15:15:33 -0800
+Subject: drm/msm/dp: employ bridge mechanism for display enable and disable
+
+From: Kuogee Hsieh <quic_khsieh@quicinc.com>
+
+[ Upstream commit 8a3b4c17f863cde8e8743edd8faffe916c49b960 ]
+
+Currently the msm_dp_*** functions implement the same sequence which would
+happen when drm_bridge is used. hence get rid of this intermediate layer
+and align with the drm_bridge usage to avoid customized implementation.
+
+Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
+
+Changes in v2:
+-- revise commit text
+-- rename dp_bridge to msm_dp_bridge
+-- delete empty functions
+
+Changes in v3:
+-- replace kzalloc() with devm_kzalloc()
+-- replace __dp_display_enable() with dp_display_enable()
+-- replace __dp_display_disable() with dp_display_disable()
+
+Changes in v4:
+-- msm_dp_bridge_init() called from msm_dp_modeset_init() same as dsi
+
+Changes in v5:
+-- delete attach, mode_fixup and pre_enable from dp_bridge_ops
+
+Changes in v6:
+-- rebase on msm-next-plus-fixes branch
+
+Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
+Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Link: https://lore.kernel.org/r/1638918933-2544-1-git-send-email-quic_khsieh@quicinc.com
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 21 ------
+ drivers/gpu/drm/msm/dp/dp_display.c         | 16 ++++-
+ drivers/gpu/drm/msm/dp/dp_display.h         |  1 +
+ drivers/gpu/drm/msm/dp/dp_drm.c             | 76 +++++++++++++++++++++
+ drivers/gpu/drm/msm/msm_drv.h               | 12 ++--
+ 5 files changed, 99 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+index 5f236395677e..119a1f5766fb 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+@@ -1003,9 +1003,6 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
+       trace_dpu_enc_mode_set(DRMID(drm_enc));
+-      if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS)
+-              msm_dp_display_mode_set(dpu_enc->dp, drm_enc, mode, adj_mode);
+-
+       list_for_each_entry(conn_iter, connector_list, head)
+               if (conn_iter->encoder == drm_enc)
+                       conn = conn_iter;
+@@ -1185,14 +1182,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+       _dpu_encoder_virt_enable_helper(drm_enc);
+-      if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) {
+-              ret = msm_dp_display_enable(dpu_enc->dp, drm_enc);
+-              if (ret) {
+-                      DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n",
+-                              ret);
+-                      goto out;
+-              }
+-      }
+       dpu_enc->enabled = true;
+ out:
+@@ -1226,11 +1215,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+       /* wait for idle */
+       dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
+-      if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) {
+-              if (msm_dp_display_pre_disable(dpu_enc->dp, drm_enc))
+-                      DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n");
+-      }
+-
+       dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP);
+       for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+@@ -1255,11 +1239,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+       DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n");
+-      if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) {
+-              if (msm_dp_display_disable(dpu_enc->dp, drm_enc))
+-                      DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n");
+-      }
+-
+       mutex_unlock(&dpu_enc->enc_lock);
+ }
+diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
+index b141ccb527b0..a51d665ab556 100644
+--- a/drivers/gpu/drm/msm/dp/dp_display.c
++++ b/drivers/gpu/drm/msm/dp/dp_display.c
+@@ -1504,6 +1504,18 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
+       dp_priv->panel->connector = dp_display->connector;
+       priv->connectors[priv->num_connectors++] = dp_display->connector;
++
++      dp_display->bridge = msm_dp_bridge_init(dp_display, dev, encoder);
++      if (IS_ERR(dp_display->bridge)) {
++              ret = PTR_ERR(dp_display->bridge);
++              DRM_DEV_ERROR(dev->dev,
++                      "failed to create dp bridge: %d\n", ret);
++              dp_display->bridge = NULL;
++              return ret;
++      }
++
++      priv->bridges[priv->num_bridges++] = dp_display->bridge;
++
+       return 0;
+ }
+@@ -1606,8 +1618,8 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder)
+ }
+ void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder,
+-                              struct drm_display_mode *mode,
+-                              struct drm_display_mode *adjusted_mode)
++                              const struct drm_display_mode *mode,
++                              const struct drm_display_mode *adjusted_mode)
+ {
+       struct dp_display_private *dp_display;
+diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
+index 8b47cdabb67e..04f4383bd3e7 100644
+--- a/drivers/gpu/drm/msm/dp/dp_display.h
++++ b/drivers/gpu/drm/msm/dp/dp_display.h
+@@ -13,6 +13,7 @@
+ struct msm_dp {
+       struct drm_device *drm_dev;
+       struct device *codec_dev;
++      struct drm_bridge *bridge;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       bool is_connected;
+diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
+index 764f4b81017e..6ab19a7ea57e 100644
+--- a/drivers/gpu/drm/msm/dp/dp_drm.c
++++ b/drivers/gpu/drm/msm/dp/dp_drm.c
+@@ -11,6 +11,14 @@
+ #include "msm_kms.h"
+ #include "dp_drm.h"
++
++struct msm_dp_bridge {
++      struct drm_bridge bridge;
++      struct msm_dp *dp_display;
++};
++
++#define to_dp_display(x)     container_of((x), struct msm_dp_bridge, bridge)
++
+ struct dp_connector {
+       struct drm_connector base;
+       struct msm_dp *dp_display;
+@@ -162,3 +170,71 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
+       return connector;
+ }
++
++static void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
++                              const struct drm_display_mode *mode,
++                              const struct drm_display_mode *adjusted_mode)
++{
++      struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
++      struct msm_dp *dp_display = dp_bridge->dp_display;
++
++      msm_dp_display_mode_set(dp_display, drm_bridge->encoder, mode, adjusted_mode);
++}
++
++static void dp_bridge_enable(struct drm_bridge *drm_bridge)
++{
++      struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
++      struct msm_dp *dp_display = dp_bridge->dp_display;
++
++      msm_dp_display_enable(dp_display, drm_bridge->encoder);
++}
++
++static void dp_bridge_disable(struct drm_bridge *drm_bridge)
++{
++      struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
++      struct msm_dp *dp_display = dp_bridge->dp_display;
++
++      msm_dp_display_pre_disable(dp_display, drm_bridge->encoder);
++}
++
++static void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
++{
++      struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
++      struct msm_dp *dp_display = dp_bridge->dp_display;
++
++      msm_dp_display_disable(dp_display, drm_bridge->encoder);
++}
++
++static const struct drm_bridge_funcs dp_bridge_ops = {
++      .enable       = dp_bridge_enable,
++      .disable      = dp_bridge_disable,
++      .post_disable = dp_bridge_post_disable,
++      .mode_set     = dp_bridge_mode_set,
++};
++
++struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
++                      struct drm_encoder *encoder)
++{
++      int rc;
++      struct msm_dp_bridge *dp_bridge;
++      struct drm_bridge *bridge;
++
++      dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL);
++      if (!dp_bridge)
++              return ERR_PTR(-ENOMEM);
++
++      dp_bridge->dp_display = dp_display;
++
++      bridge = &dp_bridge->bridge;
++      bridge->funcs = &dp_bridge_ops;
++      bridge->encoder = encoder;
++
++      rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
++      if (rc) {
++              DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
++              kfree(dp_bridge);
++              return ERR_PTR(rc);
++      }
++
++      return bridge;
++}
+diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
+index bd5132bb9bde..89b7edf755d3 100644
+--- a/drivers/gpu/drm/msm/msm_drv.h
++++ b/drivers/gpu/drm/msm/msm_drv.h
+@@ -384,8 +384,12 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder);
+ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder);
+ int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder);
+ void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder,
+-                              struct drm_display_mode *mode,
+-                              struct drm_display_mode *adjusted_mode);
++                              const struct drm_display_mode *mode,
++                              const struct drm_display_mode *adjusted_mode);
++
++struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display,
++                                      struct drm_device *dev,
++                                      struct drm_encoder *encoder);
+ void msm_dp_irq_postinstall(struct msm_dp *dp_display);
+ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display);
+@@ -422,8 +426,8 @@ static inline int msm_dp_display_pre_disable(struct msm_dp *dp,
+ }
+ static inline void msm_dp_display_mode_set(struct msm_dp *dp,
+                               struct drm_encoder *encoder,
+-                              struct drm_display_mode *mode,
+-                              struct drm_display_mode *adjusted_mode)
++                              const struct drm_display_mode *mode,
++                              const struct drm_display_mode *adjusted_mode)
+ {
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch b/queue-5.15/drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch
new file mode 100644 (file)
index 0000000..13c2175
--- /dev/null
@@ -0,0 +1,38 @@
+From 02b01b0eb6742bbee218228fbb73181219902938 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Dec 2021 14:49:01 +0300
+Subject: drm/msm/dp: Fix double free on error in msm_dp_bridge_init()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+[ Upstream commit 48d0cf4a7cf2d5447f997e232c6378bb02434655 ]
+
+The "dp_bridge" pointer is allocated with devm_kzalloc() so it will be
+freed automatically.  Kfreeing it here will only lead to a double free.
+
+Fixes: 8a3b4c17f863 ("drm/msm/dp: employ bridge mechanism for display enable and disable")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://lore.kernel.org/r/20211215114900.GD14552@kili
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/dp/dp_drm.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
+index 6ab19a7ea57e..d0ca4d0d5689 100644
+--- a/drivers/gpu/drm/msm/dp/dp_drm.c
++++ b/drivers/gpu/drm/msm/dp/dp_drm.c
+@@ -232,7 +232,6 @@ struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_devi
+       rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (rc) {
+               DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
+-              kfree(dp_bridge);
+               return ERR_PTR(rc);
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.15/drm-msm-properly-add-and-remove-internal-bridges.patch b/queue-5.15/drm-msm-properly-add-and-remove-internal-bridges.patch
new file mode 100644 (file)
index 0000000..20ca588
--- /dev/null
@@ -0,0 +1,136 @@
+From 79c275aa4cfcd00b68b97e68774b4b731bd493e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Apr 2022 02:49:53 +0300
+Subject: drm/msm: properly add and remove internal bridges
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit d28ea556267c4f2ec7264ab49f1b1296834321ec ]
+
+Add calls to drm_bridge_add()/drm_bridge_remove() DRM bridges created by
+the driver. This fixes the following warning.
+
+WARNING: CPU: 0 PID: 1 at kernel/locking/mutex.c:579 __mutex_lock+0x840/0x9f4
+DEBUG_LOCKS_WARN_ON(lock->magic != lock)
+Modules linked in:
+CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.18.0-rc1-00002-g3054695a0d27-dirty #55
+Hardware name: Generic DT based system
+ unwind_backtrace from show_stack+0x10/0x14
+ show_stack from dump_stack_lvl+0x58/0x70
+ dump_stack_lvl from __warn+0xc8/0x1e8
+ __warn from warn_slowpath_fmt+0x78/0xa8
+ warn_slowpath_fmt from __mutex_lock+0x840/0x9f4
+ __mutex_lock from mutex_lock_nested+0x1c/0x24
+ mutex_lock_nested from drm_bridge_hpd_enable+0x2c/0x84
+ drm_bridge_hpd_enable from msm_hdmi_modeset_init+0xc0/0x21c
+ msm_hdmi_modeset_init from mdp4_kms_init+0x53c/0x90c
+ mdp4_kms_init from msm_drm_bind+0x514/0x698
+ msm_drm_bind from try_to_bring_up_aggregate_device+0x160/0x1bc
+ try_to_bring_up_aggregate_device from component_master_add_with_match+0xc4/0xf8
+ component_master_add_with_match from msm_pdev_probe+0x274/0x350
+ msm_pdev_probe from platform_probe+0x5c/0xbc
+ platform_probe from really_probe.part.0+0x9c/0x290
+ really_probe.part.0 from __driver_probe_device+0xa8/0x13c
+ __driver_probe_device from driver_probe_device+0x34/0x10c
+ driver_probe_device from __driver_attach+0xbc/0x178
+ __driver_attach from bus_for_each_dev+0x74/0xc0
+ bus_for_each_dev from bus_add_driver+0x160/0x1e4
+ bus_add_driver from driver_register+0x88/0x118
+ driver_register from do_one_initcall+0x6c/0x334
+ do_one_initcall from kernel_init_freeable+0x1bc/0x220
+ kernel_init_freeable from kernel_init+0x18/0x12c
+ kernel_init from ret_from_fork+0x14/0x2c
+
+Fixes: 3d3f8b1f8b62 ("drm/bridge: make bridge registration independent of drm flow")
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Reviewed-by: Stephen Boyd <swboyd@chromium.org>
+Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Patchwork: https://patchwork.freedesktop.org/patch/481778/
+Link: https://lore.kernel.org/r/20220411234953.2425280-1-dmitry.baryshkov@linaro.org
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/dp/dp_drm.c        | 4 ++++
+ drivers/gpu/drm/msm/dsi/dsi_manager.c  | 3 +++
+ drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 3 +++
+ drivers/gpu/drm/msm/msm_drv.c          | 3 +++
+ 4 files changed, 13 insertions(+)
+
+diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
+index d0ca4d0d5689..52128edb8aeb 100644
+--- a/drivers/gpu/drm/msm/dp/dp_drm.c
++++ b/drivers/gpu/drm/msm/dp/dp_drm.c
+@@ -229,9 +229,13 @@ struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_devi
+       bridge->funcs = &dp_bridge_ops;
+       bridge->encoder = encoder;
++      drm_bridge_add(bridge);
++
+       rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (rc) {
+               DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
++              drm_bridge_remove(bridge);
++
+               return ERR_PTR(rc);
+       }
+diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
+index 6e43672f5807..fb3375cfdc84 100644
+--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
++++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
+@@ -670,6 +670,8 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
+       bridge = &dsi_bridge->base;
+       bridge->funcs = &dsi_mgr_bridge_funcs;
++      drm_bridge_add(bridge);
++
+       ret = drm_bridge_attach(encoder, bridge, NULL, 0);
+       if (ret)
+               goto fail;
+@@ -718,6 +720,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
+ void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
+ {
++      drm_bridge_remove(bridge);
+ }
+ int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
+diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+index efcfdd70a02e..0960c5642847 100644
+--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
++++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+@@ -15,6 +15,7 @@ void msm_hdmi_bridge_destroy(struct drm_bridge *bridge)
+       struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+       msm_hdmi_hpd_disable(hdmi_bridge);
++      drm_bridge_remove(bridge);
+ }
+ static void msm_hdmi_power_on(struct drm_bridge *bridge)
+@@ -354,6 +355,8 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
+               DRM_BRIDGE_OP_DETECT |
+               DRM_BRIDGE_OP_EDID;
++      drm_bridge_add(bridge);
++
+       ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (ret)
+               goto fail;
+diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
+index 916361c30d77..422507435498 100644
+--- a/drivers/gpu/drm/msm/msm_drv.c
++++ b/drivers/gpu/drm/msm/msm_drv.c
+@@ -363,6 +363,9 @@ static int msm_drm_uninit(struct device *dev)
+       drm_mode_config_cleanup(ddev);
++      for (i = 0; i < priv->num_bridges; i++)
++              drm_bridge_remove(priv->bridges[i]);
++
+       pm_runtime_get_sync(dev);
+       msm_irq_uninstall(ddev);
+       pm_runtime_put_sync(dev);
+-- 
+2.35.1
+
diff --git a/queue-5.15/dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch b/queue-5.15/dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch
new file mode 100644 (file)
index 0000000..4a27a8b
--- /dev/null
@@ -0,0 +1,45 @@
+From df903584abf4c239a3e51d67cfe993bf962e6a91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Aug 2021 22:29:42 +0530
+Subject: dt-bindings: soc: qcom: smd-rpm: Add compatible for MSM8953 SoC
+
+From: Vladimir Lypak <vladimir.lypak@gmail.com>
+
+[ Upstream commit 96c42812f798c5e48d55cd6fc2101ce99af19608 ]
+
+Document compatible for MSM8953 SoC.
+
+Signed-off-by: Vladimir Lypak <vladimir.lypak@gmail.com>
+Signed-off-by: Adam Skladowski <a_skl39@protonmail.com>
+Signed-off-by: Sireesh Kodali <sireeshkodali1@gmail.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Link: https://lore.kernel.org/r/20210825165943.19415-1-sireeshkodali1@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+index cc3fe5ed7421..77963b86b714 100644
+--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
++++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+@@ -34,6 +34,7 @@ properties:
+       - qcom,rpm-ipq6018
+       - qcom,rpm-msm8226
+       - qcom,rpm-msm8916
++      - qcom,rpm-msm8953
+       - qcom,rpm-msm8974
+       - qcom,rpm-msm8976
+       - qcom,rpm-msm8996
+@@ -57,6 +58,7 @@ if:
+           - qcom,rpm-apq8084
+           - qcom,rpm-msm8916
+           - qcom,rpm-msm8974
++          - qcom,rpm-msm8953
+ then:
+   required:
+     - qcom,smd-channels
+-- 
+2.35.1
+
diff --git a/queue-5.15/dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch b/queue-5.15/dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch
new file mode 100644 (file)
index 0000000..9acb8f7
--- /dev/null
@@ -0,0 +1,38 @@
+From 32559c085c248fe65c499ac5d37128430f7fc911 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Apr 2022 00:18:57 +0100
+Subject: dt-bindings: soc: qcom: smd-rpm: Fix missing MSM8936 compatible
+
+From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+
+[ Upstream commit e930244918092d44b60a7b538cf60d737010ceef ]
+
+Add compatible msm8936. msm8936 covers both msm8936 and msm8939.
+The relevant driver already has the compat string but, we haven't
+documented it.
+
+Fixes: d6e52482f5ab ("drivers: soc: Add MSM8936 SMD RPM compatible")
+Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20220418231857.3061053-1-bryan.odonoghue@linaro.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+index 77963b86b714..1b0062e3c1a4 100644
+--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
++++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+@@ -34,6 +34,7 @@ properties:
+       - qcom,rpm-ipq6018
+       - qcom,rpm-msm8226
+       - qcom,rpm-msm8916
++      - qcom,rpm-msm8936
+       - qcom,rpm-msm8953
+       - qcom,rpm-msm8974
+       - qcom,rpm-msm8976
+-- 
+2.35.1
+
diff --git a/queue-5.15/gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch b/queue-5.15/gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch
new file mode 100644 (file)
index 0000000..9992289
--- /dev/null
@@ -0,0 +1,34 @@
+From 31d722b87ad7f966a92c11fac9f013b997031f82 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Mar 2022 14:47:24 +0100
+Subject: gfs2: Fix gfs2_file_buffered_write endless loop workaround
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+[ Upstream commit 46f3e0421ccb5474b5c006b0089b9dfd42534bb6 ]
+
+Since commit 554c577cee95b, gfs2_file_buffered_write() can accidentally
+return a truncated iov_iter, which might confuse callers.  Fix that.
+
+Fixes: 554c577cee95b ("gfs2: Prevent endless loops in gfs2_file_buffered_write")
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/gfs2/file.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
+index 60390f9dc31f..e93185d804e0 100644
+--- a/fs/gfs2/file.c
++++ b/fs/gfs2/file.c
+@@ -1086,6 +1086,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
+       gfs2_holder_uninit(gh);
+       if (statfs_gh)
+               kfree(statfs_gh);
++      from->count = orig_count - read;
+       return read ? read : ret;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/ibmvnic-allow-queueing-resets-during-probe.patch b/queue-5.15/ibmvnic-allow-queueing-resets-during-probe.patch
new file mode 100644 (file)
index 0000000..eb1ebdf
--- /dev/null
@@ -0,0 +1,274 @@
+From 18c541aa17246888c009a4d26127235463eeb4e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Feb 2022 22:23:58 -0800
+Subject: ibmvnic: Allow queueing resets during probe
+
+From: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
+
+[ Upstream commit fd98693cb0721317f27341951593712c580c36a1 ]
+
+We currently don't allow queuing resets when adapter is in VNIC_PROBING
+state - instead we throw away the reset and return EBUSY. The reasoning
+is probably that during ibmvnic_probe() the ibmvnic_adapter itself is
+being initialized so performing a reset during this time can lead us to
+accessing fields in the ibmvnic_adapter that are not fully initialized.
+A review of the code shows that all the adapter state neede to process a
+reset is initialized before registering the CRQ so that should no longer
+be a concern.
+
+Further the expectation is that if we do get a reset (transport event)
+during probe, the do..while() loop in ibmvnic_probe() will handle this
+by reinitializing the CRQ.
+
+While that is true to some extent, it is possible that the reset might
+occur _after_ the CRQ is registered and CRQ_INIT message was exchanged
+but _before_ the adapter state is set to VNIC_PROBED. As mentioned above,
+such a reset will be thrown away. While the client assumes that the
+adapter is functional, the vnic server will wait for the client to reinit
+the adapter. This disconnect between the two leaves the adapter down
+needing manual intervention.
+
+Because ibmvnic_probe() has other work to do after initializing the CRQ
+(such as registering the netdev at a minimum) and because the reset event
+can occur at any instant after the CRQ is initialized, there will always
+be a window between initializing the CRQ and considering the adapter
+ready for resets (ie state == PROBED).
+
+So rather than discarding resets during this window, allow queueing them
+- but only process them after the adapter is fully initialized.
+
+To do this, introduce a new completion state ->probe_done and have the
+reset worker thread wait on this before processing resets.
+
+This change brings up two new situations in or just after ibmvnic_probe().
+First after one or more resets were queued, we encounter an error and
+decide to retry the initialization.  At that point the queued resets are
+no longer relevant since we could be talking to a new vnic server. So we
+must purge/flush the queued resets before restarting the initialization.
+As a side note, since we are still in the probing stage and we have not
+registered the netdev, it will not be CHANGE_PARAM reset.
+
+Second this change opens up a potential race between the worker thread
+in __ibmvnic_reset(), the tasklet and the ibmvnic_open() due to the
+following sequence of events:
+
+       1. Register CRQ
+       2. Get transport event before CRQ_INIT completes.
+       3. Tasklet schedules reset:
+               a) add rwi to list
+               b) schedule_work() to start worker thread which runs
+                  and waits for ->probe_done.
+       4. ibmvnic_probe() decides to retry, purges rwi_list
+       5. Re-register crq and this time rest of probe succeeds - register
+          netdev and complete(->probe_done).
+       6. Worker thread resumes in __ibmvnic_reset() from 3b.
+       7. Worker thread sets ->resetting bit
+       8. ibmvnic_open() comes in, notices ->resetting bit, sets state
+          to IBMVNIC_OPEN and returns early expecting worker thread to
+          finish the open.
+       9. Worker thread finds rwi_list empty and returns without
+          opening the interface.
+
+If this happens, the ->ndo_open() call is effectively lost and the
+interface remains down. To address this, ensure that ->rwi_list is
+not empty before setting the ->resetting  bit. See also comments in
+__ibmvnic_reset().
+
+Fixes: 6a2fb0e99f9c ("ibmvnic: driver initialization for kdump/kexec")
+Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/ibm/ibmvnic.c | 107 ++++++++++++++++++++++++++---
+ drivers/net/ethernet/ibm/ibmvnic.h |   1 +
+ 2 files changed, 98 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
+index 9f4f40564d74..28344c3dfea1 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.c
++++ b/drivers/net/ethernet/ibm/ibmvnic.c
+@@ -2471,23 +2471,82 @@ static int do_passive_init(struct ibmvnic_adapter *adapter)
+ static void __ibmvnic_reset(struct work_struct *work)
+ {
+       struct ibmvnic_adapter *adapter;
+-      bool saved_state = false;
++      unsigned int timeout = 5000;
+       struct ibmvnic_rwi *tmprwi;
++      bool saved_state = false;
+       struct ibmvnic_rwi *rwi;
+       unsigned long flags;
+-      u32 reset_state;
++      struct device *dev;
++      bool need_reset;
+       int num_fails = 0;
++      u32 reset_state;
+       int rc = 0;
+       adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
++              dev = &adapter->vdev->dev;
+-      if (test_and_set_bit_lock(0, &adapter->resetting)) {
++      /* Wait for ibmvnic_probe() to complete. If probe is taking too long
++       * or if another reset is in progress, defer work for now. If probe
++       * eventually fails it will flush and terminate our work.
++       *
++       * Three possibilities here:
++       * 1. Adpater being removed  - just return
++       * 2. Timed out on probe or another reset in progress - delay the work
++       * 3. Completed probe - perform any resets in queue
++       */
++      if (adapter->state == VNIC_PROBING &&
++          !wait_for_completion_timeout(&adapter->probe_done, timeout)) {
++              dev_err(dev, "Reset thread timed out on probe");
+               queue_delayed_work(system_long_wq,
+                                  &adapter->ibmvnic_delayed_reset,
+                                  IBMVNIC_RESET_DELAY);
+               return;
+       }
++      /* adapter is done with probe (i.e state is never VNIC_PROBING now) */
++      if (adapter->state == VNIC_REMOVING)
++              return;
++
++      /* ->rwi_list is stable now (no one else is removing entries) */
++
++      /* ibmvnic_probe() may have purged the reset queue after we were
++       * scheduled to process a reset so there maybe no resets to process.
++       * Before setting the ->resetting bit though, we have to make sure
++       * that there is infact a reset to process. Otherwise we may race
++       * with ibmvnic_open() and end up leaving the vnic down:
++       *
++       *      __ibmvnic_reset()           ibmvnic_open()
++       *      -----------------           --------------
++       *
++       *  set ->resetting bit
++       *                              find ->resetting bit is set
++       *                              set ->state to IBMVNIC_OPEN (i.e
++       *                              assume reset will open device)
++       *                              return
++       *  find reset queue empty
++       *  return
++       *
++       *      Neither performed vnic login/open and vnic stays down
++       *
++       * If we hold the lock and conditionally set the bit, either we
++       * or ibmvnic_open() will complete the open.
++       */
++      need_reset = false;
++      spin_lock(&adapter->rwi_lock);
++      if (!list_empty(&adapter->rwi_list)) {
++              if (test_and_set_bit_lock(0, &adapter->resetting)) {
++                      queue_delayed_work(system_long_wq,
++                                         &adapter->ibmvnic_delayed_reset,
++                                         IBMVNIC_RESET_DELAY);
++              } else {
++                      need_reset = true;
++              }
++      }
++      spin_unlock(&adapter->rwi_lock);
++
++      if (!need_reset)
++              return;
++
+       rwi = get_next_rwi(adapter);
+       while (rwi) {
+               spin_lock_irqsave(&adapter->state_lock, flags);
+@@ -2639,13 +2698,6 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
+               goto err;
+       }
+-      if (adapter->state == VNIC_PROBING) {
+-              netdev_warn(netdev, "Adapter reset during probe\n");
+-              adapter->init_done_rc = -EAGAIN;
+-              ret = EAGAIN;
+-              goto err;
+-      }
+-
+       list_for_each_entry(tmp, &adapter->rwi_list, list) {
+               if (tmp->reset_reason == reason) {
+                       netdev_dbg(netdev, "Skipping matching reset, reason=%s\n",
+@@ -5561,6 +5613,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+       struct ibmvnic_adapter *adapter;
+       struct net_device *netdev;
+       unsigned char *mac_addr_p;
++      unsigned long flags;
+       bool init_success;
+       int rc;
+@@ -5602,6 +5655,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+       spin_lock_init(&adapter->rwi_lock);
+       spin_lock_init(&adapter->state_lock);
+       mutex_init(&adapter->fw_lock);
++      init_completion(&adapter->probe_done);
+       init_completion(&adapter->init_done);
+       init_completion(&adapter->fw_done);
+       init_completion(&adapter->reset_done);
+@@ -5617,6 +5671,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+                */
+               adapter->failover_pending = false;
++              /* If we had already initialized CRQ, we may have one or
++               * more resets queued already. Discard those and release
++               * the CRQ before initializing the CRQ again.
++               */
++              release_crq_queue(adapter);
++
++              /* Since we are still in PROBING state, __ibmvnic_reset()
++               * will not access the ->rwi_list and since we released CRQ,
++               * we won't get _new_ transport events. But there maybe an
++               * ongoing ibmvnic_reset() call. So serialize access to
++               * rwi_list. If we win the race, ibvmnic_reset() could add
++               * a reset after we purged but thats ok - we just may end
++               * up with an extra reset (i.e similar to having two or more
++               * resets in the queue at once).
++               * CHECK.
++               */
++              spin_lock_irqsave(&adapter->rwi_lock, flags);
++              flush_reset_queue(adapter);
++              spin_unlock_irqrestore(&adapter->rwi_lock, flags);
++
+               rc = init_crq_queue(adapter);
+               if (rc) {
+                       dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
+@@ -5668,6 +5742,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+       }
+       dev_info(&dev->dev, "ibmvnic registered\n");
++      complete(&adapter->probe_done);
++
+       return 0;
+ ibmvnic_register_fail:
+@@ -5682,6 +5758,17 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+ ibmvnic_init_fail:
+       release_sub_crqs(adapter, 1);
+       release_crq_queue(adapter);
++
++      /* cleanup worker thread after releasing CRQ so we don't get
++       * transport events (i.e new work items for the worker thread).
++       */
++      adapter->state = VNIC_REMOVING;
++      complete(&adapter->probe_done);
++      flush_work(&adapter->ibmvnic_reset);
++      flush_delayed_work(&adapter->ibmvnic_delayed_reset);
++
++      flush_reset_queue(adapter);
++
+       mutex_destroy(&adapter->fw_lock);
+       free_netdev(netdev);
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
+index 1a9ed9202654..b01c439965ff 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.h
++++ b/drivers/net/ethernet/ibm/ibmvnic.h
+@@ -927,6 +927,7 @@ struct ibmvnic_adapter {
+       struct ibmvnic_tx_pool *tx_pool;
+       struct ibmvnic_tx_pool *tso_pool;
++      struct completion probe_done;
+       struct completion init_done;
+       int init_done_rc;
+-- 
+2.35.1
+
diff --git a/queue-5.15/ibmvnic-clear-fop-when-retrying-probe.patch b/queue-5.15/ibmvnic-clear-fop-when-retrying-probe.patch
new file mode 100644 (file)
index 0000000..ecbe8dc
--- /dev/null
@@ -0,0 +1,46 @@
+From f506ab7d60835d4fb1d03a52e783b22c0304636e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Feb 2022 22:23:57 -0800
+Subject: ibmvnic: clear fop when retrying probe
+
+From: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
+
+[ Upstream commit f628ad531b4f34fdba0984255b4a2850dd369513 ]
+
+Clear ->failover_pending flag that may have been set in the previous
+pass of registering CRQ. If we don't clear, a subsequent ibmvnic_open()
+call would be misled into thinking a failover is pending and assuming
+that the reset worker thread would open the adapter. If this pass of
+registering the CRQ succeeds (i.e there is no transport event), there
+wouldn't be a reset worker thread.
+
+This would leave the adapter unconfigured and require manual intervention
+to bring it up during boot.
+
+Fixes: 5a18e1e0c193 ("ibmvnic: Fix failover case for non-redundant configuration")
+Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/ibm/ibmvnic.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
+index 70267bd73429..9f4f40564d74 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.c
++++ b/drivers/net/ethernet/ibm/ibmvnic.c
+@@ -5612,6 +5612,11 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+       do {
+               reinit_init_done(adapter);
++              /* clear any failovers we got in the previous pass
++               * since we are reinitializing the CRQ
++               */
++              adapter->failover_pending = false;
++
+               rc = init_crq_queue(adapter);
+               if (rc) {
+                       dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
+-- 
+2.35.1
+
diff --git a/queue-5.15/ibmvnic-init-init_done_rc-earlier.patch b/queue-5.15/ibmvnic-init-init_done_rc-earlier.patch
new file mode 100644 (file)
index 0000000..90df048
--- /dev/null
@@ -0,0 +1,110 @@
+From 21e26d270aa7735f423b3e35d7e4355f11ad7b47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Feb 2022 22:23:56 -0800
+Subject: ibmvnic: init init_done_rc earlier
+
+From: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
+
+[ Upstream commit ae16bf15374d8b055e040ac6f3f1147ab1c9bb7d ]
+
+We currently initialize the ->init_done completion/return code fields
+before issuing a CRQ_INIT command. But if we get a transport event soon
+after registering the CRQ the taskslet may already have recorded the
+completion and error code. If we initialize here, we might overwrite/
+lose that and end up issuing the CRQ_INIT only to timeout later.
+
+If that timeout happens during probe, we will leave the adapter in the
+DOWN state rather than retrying to register/init the CRQ.
+
+Initialize the completion before registering the CRQ so we don't lose
+the notification.
+
+Fixes: 032c5e82847a ("Driver for IBM System i/p VNIC protocol")
+Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/ibm/ibmvnic.c | 26 +++++++++++++++++++++-----
+ 1 file changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
+index b262aa84b6a2..70267bd73429 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.c
++++ b/drivers/net/ethernet/ibm/ibmvnic.c
+@@ -2063,6 +2063,19 @@ static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
+       return "UNKNOWN";
+ }
++/*
++ * Initialize the init_done completion and return code values. We
++ * can get a transport event just after registering the CRQ and the
++ * tasklet will use this to communicate the transport event. To ensure
++ * we don't miss the notification/error, initialize these _before_
++ * regisering the CRQ.
++ */
++static inline void reinit_init_done(struct ibmvnic_adapter *adapter)
++{
++      reinit_completion(&adapter->init_done);
++      adapter->init_done_rc = 0;
++}
++
+ /*
+  * do_reset returns zero if we are able to keep processing reset events, or
+  * non-zero if we hit a fatal error and must halt.
+@@ -2169,6 +2182,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
+                */
+               adapter->state = VNIC_PROBED;
++              reinit_init_done(adapter);
++
+               if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
+                       rc = init_crq_queue(adapter);
+               } else if (adapter->reset_reason == VNIC_RESET_MOBILITY) {
+@@ -2314,7 +2329,8 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
+        */
+       adapter->state = VNIC_PROBED;
+-      reinit_completion(&adapter->init_done);
++      reinit_init_done(adapter);
++
+       rc = init_crq_queue(adapter);
+       if (rc) {
+               netdev_err(adapter->netdev,
+@@ -5485,10 +5501,6 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
+       adapter->from_passive_init = false;
+-      if (reset)
+-              reinit_completion(&adapter->init_done);
+-
+-      adapter->init_done_rc = 0;
+       rc = ibmvnic_send_crq_init(adapter);
+       if (rc) {
+               dev_err(dev, "Send crq init failed with error %d\n", rc);
+@@ -5502,12 +5514,14 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
+       if (adapter->init_done_rc) {
+               release_crq_queue(adapter);
++              dev_err(dev, "CRQ-init failed, %d\n", adapter->init_done_rc);
+               return adapter->init_done_rc;
+       }
+       if (adapter->from_passive_init) {
+               adapter->state = VNIC_OPEN;
+               adapter->from_passive_init = false;
++              dev_err(dev, "CRQ-init failed, passive-init\n");
+               return -1;
+       }
+@@ -5596,6 +5610,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+       init_success = false;
+       do {
++              reinit_init_done(adapter);
++
+               rc = init_crq_queue(adapter);
+               if (rc) {
+                       dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
+-- 
+2.35.1
+
diff --git a/queue-5.15/iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch b/queue-5.15/iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch
new file mode 100644 (file)
index 0000000..41bbc42
--- /dev/null
@@ -0,0 +1,58 @@
+From 8a2644dc664f70c88f6c8bfe81136d3d180fa05e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Feb 2022 10:42:21 +0800
+Subject: iio: accel: mma8452: use the correct logic to get mma8452_data
+
+From: Haibo Chen <haibo.chen@nxp.com>
+
+[ Upstream commit c87b7b12f48db86ac9909894f4dc0107d7df6375 ]
+
+The original logic to get mma8452_data is wrong, the *dev point to
+the device belong to iio_dev. we can't use this dev to find the
+correct i2c_client. The original logic happen to work because it
+finally use dev->driver_data to get iio_dev. Here use the API
+to_i2c_client() is wrong and make reader confuse. To correct the
+logic, it should be like this
+
+  struct mma8452_data *data = iio_priv(dev_get_drvdata(dev));
+
+But after commit 8b7651f25962 ("iio: iio_device_alloc(): Remove
+unnecessary self drvdata"), the upper logic also can't work.
+When try to show the avialable scale in userspace, will meet kernel
+dump, kernel handle NULL pointer dereference.
+
+So use dev_to_iio_dev() to correct the logic.
+
+Dual fixes tags as the second reflects when the bug was exposed, whilst
+the first reflects when the original bug was introduced.
+
+Fixes: c3cdd6e48e35 ("iio: mma8452: refactor for seperating chip specific data")
+Fixes: 8b7651f25962 ("iio: iio_device_alloc(): Remove unnecessary self drvdata")
+Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
+Reviewed-by: Martin Kepplinger <martink@posteo.de>
+Cc: <Stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/1645497741-5402-1-git-send-email-haibo.chen@nxp.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/accel/mma8452.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
+index 373b59557afe..1f46a73aafea 100644
+--- a/drivers/iio/accel/mma8452.c
++++ b/drivers/iio/accel/mma8452.c
+@@ -380,8 +380,8 @@ static ssize_t mma8452_show_scale_avail(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+ {
+-      struct mma8452_data *data = iio_priv(i2c_get_clientdata(
+-                                           to_i2c_client(dev)));
++      struct iio_dev *indio_dev = dev_to_iio_dev(dev);
++      struct mma8452_data *data = iio_priv(indio_dev);
+       return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
+               ARRAY_SIZE(data->chip_info->mma_scales));
+-- 
+2.35.1
+
diff --git a/queue-5.15/input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch b/queue-5.15/input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch
new file mode 100644 (file)
index 0000000..13eed01
--- /dev/null
@@ -0,0 +1,43 @@
+From b27c4e31a22743c4c9c698f417a15a761c41b081 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Sep 2021 18:57:32 -0700
+Subject: Input: cpcap-pwrbutton - handle errors from platform_get_irq()
+
+From: Tang Bin <tangbin@cmss.chinamobile.com>
+
+[ Upstream commit 58ae4004b9c4bb040958cf73986b687a5ea4d85d ]
+
+The function cpcap_power_button_probe() does not perform
+sufficient error checking after executing platform_get_irq(),
+thus fix it.
+
+Signed-off-by: Tang Bin <tangbin@cmss.chinamobile.com>
+Link: https://lore.kernel.org/r/20210802121740.8700-1-tangbin@cmss.chinamobile.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/input/misc/cpcap-pwrbutton.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c
+index 0abef63217e2..372cb44d0635 100644
+--- a/drivers/input/misc/cpcap-pwrbutton.c
++++ b/drivers/input/misc/cpcap-pwrbutton.c
+@@ -54,9 +54,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button)
+ static int cpcap_power_button_probe(struct platform_device *pdev)
+ {
+       struct cpcap_power_button *button;
+-      int irq = platform_get_irq(pdev, 0);
++      int irq;
+       int err;
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              return irq;
++
+       button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
+       if (!button)
+               return -ENOMEM;
+-- 
+2.35.1
+
diff --git a/queue-5.15/input-goodix-add-a-goodix.h-header-file.patch b/queue-5.15/input-goodix-add-a-goodix.h-header-file.patch
new file mode 100644 (file)
index 0000000..132b29c
--- /dev/null
@@ -0,0 +1,282 @@
+From 53f96b12f3e006d5d0d2a9c596e59cb80f4209e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Sep 2021 21:08:18 -0700
+Subject: Input: goodix - add a goodix.h header file
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit a2233cb7b65a017067e2f2703375ecc930a0ab30 ]
+
+Add a goodix.h header file, and move the register definitions,
+and struct declarations there and add prototypes for various
+helper functions.
+
+This is a preparation patch for adding support for controllers
+without flash, which need to have their firmware uploaded and
+need some other special handling too.
+
+Since MAINTAINERS needs updating because of this change anyways,
+also add myself as co-maintainer.
+
+Reviewed-by: Bastien Nocera <hadess@hadess.net>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20210920150643.155872-3-hdegoede@redhat.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ MAINTAINERS                        |  3 +-
+ drivers/input/touchscreen/goodix.c | 74 +++---------------------------
+ drivers/input/touchscreen/goodix.h | 73 +++++++++++++++++++++++++++++
+ 3 files changed, 81 insertions(+), 69 deletions(-)
+ create mode 100644 drivers/input/touchscreen/goodix.h
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index a60d7e0466af..edc32575828b 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -7952,9 +7952,10 @@ F:      drivers/media/usb/go7007/
+ GOODIX TOUCHSCREEN
+ M:    Bastien Nocera <hadess@hadess.net>
++M:    Hans de Goede <hdegoede@redhat.com>
+ L:    linux-input@vger.kernel.org
+ S:    Maintained
+-F:    drivers/input/touchscreen/goodix.c
++F:    drivers/input/touchscreen/goodix*
+ GOOGLE ETHERNET DRIVERS
+ M:    Jeroen de Borst <jeroendb@google.com>
+diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
+index 1eb776abe562..5ccdd6abd868 100644
+--- a/drivers/input/touchscreen/goodix.c
++++ b/drivers/input/touchscreen/goodix.c
+@@ -14,20 +14,15 @@
+ #include <linux/kernel.h>
+ #include <linux/dmi.h>
+ #include <linux/firmware.h>
+-#include <linux/gpio/consumer.h>
+-#include <linux/i2c.h>
+-#include <linux/input.h>
+-#include <linux/input/mt.h>
+-#include <linux/input/touchscreen.h>
+ #include <linux/module.h>
+ #include <linux/delay.h>
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+-#include <linux/regulator/consumer.h>
+ #include <linux/slab.h>
+ #include <linux/acpi.h>
+ #include <linux/of.h>
+ #include <asm/unaligned.h>
++#include "goodix.h"
+ #define GOODIX_GPIO_INT_NAME          "irq"
+ #define GOODIX_GPIO_RST_NAME          "reset"
+@@ -38,22 +33,11 @@
+ #define GOODIX_CONTACT_SIZE           8
+ #define GOODIX_MAX_CONTACT_SIZE               9
+ #define GOODIX_MAX_CONTACTS           10
+-#define GOODIX_MAX_KEYS                       7
+ #define GOODIX_CONFIG_MIN_LENGTH      186
+ #define GOODIX_CONFIG_911_LENGTH      186
+ #define GOODIX_CONFIG_967_LENGTH      228
+ #define GOODIX_CONFIG_GT9X_LENGTH     240
+-#define GOODIX_CONFIG_MAX_LENGTH      240
+-
+-/* Register defines */
+-#define GOODIX_REG_COMMAND            0x8040
+-#define GOODIX_CMD_SCREEN_OFF         0x05
+-
+-#define GOODIX_READ_COOR_ADDR         0x814E
+-#define GOODIX_GT1X_REG_CONFIG_DATA   0x8050
+-#define GOODIX_GT9X_REG_CONFIG_DATA   0x8047
+-#define GOODIX_REG_ID                 0x8140
+ #define GOODIX_BUFFER_STATUS_READY    BIT(7)
+ #define GOODIX_HAVE_KEY                       BIT(4)
+@@ -68,55 +52,11 @@
+ #define ACPI_GPIO_SUPPORT
+ #endif
+-struct goodix_ts_data;
+-
+-enum goodix_irq_pin_access_method {
+-      IRQ_PIN_ACCESS_NONE,
+-      IRQ_PIN_ACCESS_GPIO,
+-      IRQ_PIN_ACCESS_ACPI_GPIO,
+-      IRQ_PIN_ACCESS_ACPI_METHOD,
+-};
+-
+-struct goodix_chip_data {
+-      u16 config_addr;
+-      int config_len;
+-      int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
+-      void (*calc_config_checksum)(struct goodix_ts_data *ts);
+-};
+-
+ struct goodix_chip_id {
+       const char *id;
+       const struct goodix_chip_data *data;
+ };
+-#define GOODIX_ID_MAX_LEN     4
+-
+-struct goodix_ts_data {
+-      struct i2c_client *client;
+-      struct input_dev *input_dev;
+-      const struct goodix_chip_data *chip;
+-      struct touchscreen_properties prop;
+-      unsigned int max_touch_num;
+-      unsigned int int_trigger_type;
+-      struct regulator *avdd28;
+-      struct regulator *vddio;
+-      struct gpio_desc *gpiod_int;
+-      struct gpio_desc *gpiod_rst;
+-      int gpio_count;
+-      int gpio_int_idx;
+-      char id[GOODIX_ID_MAX_LEN + 1];
+-      u16 version;
+-      const char *cfg_name;
+-      bool reset_controller_at_probe;
+-      bool load_cfg_from_disk;
+-      struct completion firmware_loading_complete;
+-      unsigned long irq_flags;
+-      enum goodix_irq_pin_access_method irq_pin_access_method;
+-      unsigned int contact_size;
+-      u8 config[GOODIX_CONFIG_MAX_LENGTH];
+-      unsigned short keymap[GOODIX_MAX_KEYS];
+-};
+-
+ static int goodix_check_cfg_8(struct goodix_ts_data *ts,
+                             const u8 *cfg, int len);
+ static int goodix_check_cfg_16(struct goodix_ts_data *ts,
+@@ -216,8 +156,7 @@ static const struct dmi_system_id inverted_x_screen[] = {
+  * @buf: raw write data buffer.
+  * @len: length of the buffer to write
+  */
+-static int goodix_i2c_read(struct i2c_client *client,
+-                         u16 reg, u8 *buf, int len)
++int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len)
+ {
+       struct i2c_msg msgs[2];
+       __be16 wbuf = cpu_to_be16(reg);
+@@ -245,8 +184,7 @@ static int goodix_i2c_read(struct i2c_client *client,
+  * @buf: raw data buffer to write.
+  * @len: length of the buffer to write
+  */
+-static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
+-                          int len)
++int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len)
+ {
+       u8 *addr_buf;
+       struct i2c_msg msg;
+@@ -270,7 +208,7 @@ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
+       return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
+ }
+-static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
++int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
+ {
+       return goodix_i2c_write(client, reg, &value, sizeof(value));
+ }
+@@ -554,7 +492,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
+  * @cfg: config firmware to write to device
+  * @len: config data length
+  */
+-static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
++int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
+ {
+       int error;
+@@ -652,7 +590,7 @@ static int goodix_irq_direction_input(struct goodix_ts_data *ts)
+       return -EINVAL; /* Never reached */
+ }
+-static int goodix_int_sync(struct goodix_ts_data *ts)
++int goodix_int_sync(struct goodix_ts_data *ts)
+ {
+       int error;
+diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
+new file mode 100644
+index 000000000000..cdaced4f2980
+--- /dev/null
++++ b/drivers/input/touchscreen/goodix.h
+@@ -0,0 +1,73 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++#ifndef __GOODIX_H__
++#define __GOODIX_H__
++
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/input.h>
++#include <linux/input/mt.h>
++#include <linux/input/touchscreen.h>
++#include <linux/regulator/consumer.h>
++
++/* Register defines */
++#define GOODIX_REG_COMMAND                    0x8040
++#define GOODIX_CMD_SCREEN_OFF                 0x05
++
++#define GOODIX_GT1X_REG_CONFIG_DATA           0x8050
++#define GOODIX_GT9X_REG_CONFIG_DATA           0x8047
++#define GOODIX_REG_ID                         0x8140
++#define GOODIX_READ_COOR_ADDR                 0x814E
++
++#define GOODIX_ID_MAX_LEN                     4
++#define GOODIX_CONFIG_MAX_LENGTH              240
++#define GOODIX_MAX_KEYS                               7
++
++enum goodix_irq_pin_access_method {
++      IRQ_PIN_ACCESS_NONE,
++      IRQ_PIN_ACCESS_GPIO,
++      IRQ_PIN_ACCESS_ACPI_GPIO,
++      IRQ_PIN_ACCESS_ACPI_METHOD,
++};
++
++struct goodix_ts_data;
++
++struct goodix_chip_data {
++      u16 config_addr;
++      int config_len;
++      int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
++      void (*calc_config_checksum)(struct goodix_ts_data *ts);
++};
++
++struct goodix_ts_data {
++      struct i2c_client *client;
++      struct input_dev *input_dev;
++      const struct goodix_chip_data *chip;
++      struct touchscreen_properties prop;
++      unsigned int max_touch_num;
++      unsigned int int_trigger_type;
++      struct regulator *avdd28;
++      struct regulator *vddio;
++      struct gpio_desc *gpiod_int;
++      struct gpio_desc *gpiod_rst;
++      int gpio_count;
++      int gpio_int_idx;
++      char id[GOODIX_ID_MAX_LEN + 1];
++      u16 version;
++      const char *cfg_name;
++      bool reset_controller_at_probe;
++      bool load_cfg_from_disk;
++      struct completion firmware_loading_complete;
++      unsigned long irq_flags;
++      enum goodix_irq_pin_access_method irq_pin_access_method;
++      unsigned int contact_size;
++      u8 config[GOODIX_CONFIG_MAX_LENGTH];
++      unsigned short keymap[GOODIX_MAX_KEYS];
++};
++
++int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
++int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len);
++int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value);
++int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len);
++int goodix_int_sync(struct goodix_ts_data *ts);
++
++#endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/input-goodix-change-goodix_i2c_write-len-parameter-t.patch b/queue-5.15/input-goodix-change-goodix_i2c_write-len-parameter-t.patch
new file mode 100644 (file)
index 0000000..33d75ac
--- /dev/null
@@ -0,0 +1,38 @@
+From bf8bef3bc64d3569f2a27af9ac2a8ca014370de4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Sep 2021 21:08:02 -0700
+Subject: Input: goodix - change goodix_i2c_write() len parameter type to int
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit 31ae0102a34ed863c7d32b10e768036324991679 ]
+
+Change the type of the goodix_i2c_write() len parameter to from 'unsigned'
+to 'int' to avoid bare use of 'unsigned', changing it to 'int' makes
+goodix_i2c_write()' prototype consistent with goodix_i2c_read().
+
+Reviewed-by: Bastien Nocera <hadess@hadess.net>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20210920150643.155872-2-hdegoede@redhat.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/input/touchscreen/goodix.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
+index 5051a1766aac..1eb776abe562 100644
+--- a/drivers/input/touchscreen/goodix.c
++++ b/drivers/input/touchscreen/goodix.c
+@@ -246,7 +246,7 @@ static int goodix_i2c_read(struct i2c_client *client,
+  * @len: length of the buffer to write
+  */
+ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
+-                          unsigned len)
++                          int len)
+ {
+       u8 *addr_buf;
+       struct i2c_msg msg;
+-- 
+2.35.1
+
diff --git a/queue-5.15/input-goodix-refactor-reset-handling.patch b/queue-5.15/input-goodix-refactor-reset-handling.patch
new file mode 100644 (file)
index 0000000..07ebe4b
--- /dev/null
@@ -0,0 +1,162 @@
+From 3b2404e3b669cd19116ce4a758653b0948d5502e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Sep 2021 21:08:26 -0700
+Subject: Input: goodix - refactor reset handling
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit 209bda4741f68f102cf2f272227bfc938e387b51 ]
+
+Refactor reset handling a bit, change the main reset handler
+into a new goodix_reset_no_int_sync() helper and add a
+goodix_reset() wrapper which calls goodix_int_sync()
+separately.
+
+Also push the dev_err() call on reset failure into the
+goodix_reset_no_int_sync() and goodix_int_sync() functions,
+so that we don't need to have separate dev_err() calls in
+all their callers.
+
+This is a preparation patch for adding support for controllers
+without flash, which need to have their firmware uploaded and
+need some other special handling too.
+
+Reviewed-by: Bastien Nocera <hadess@hadess.net>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20210920150643.155872-4-hdegoede@redhat.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/input/touchscreen/goodix.c | 48 ++++++++++++++++++++----------
+ drivers/input/touchscreen/goodix.h |  1 +
+ 2 files changed, 33 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
+index 5ccdd6abd868..2ca903a8af21 100644
+--- a/drivers/input/touchscreen/goodix.c
++++ b/drivers/input/touchscreen/goodix.c
+@@ -596,56 +596,76 @@ int goodix_int_sync(struct goodix_ts_data *ts)
+       error = goodix_irq_direction_output(ts, 0);
+       if (error)
+-              return error;
++              goto error;
+       msleep(50);                             /* T5: 50ms */
+       error = goodix_irq_direction_input(ts);
+       if (error)
+-              return error;
++              goto error;
+       return 0;
++
++error:
++      dev_err(&ts->client->dev, "Controller irq sync failed.\n");
++      return error;
+ }
+ /**
+- * goodix_reset - Reset device during power on
++ * goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode
+  *
+  * @ts: goodix_ts_data pointer
+  */
+-static int goodix_reset(struct goodix_ts_data *ts)
++int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
+ {
+       int error;
+       /* begin select I2C slave addr */
+       error = gpiod_direction_output(ts->gpiod_rst, 0);
+       if (error)
+-              return error;
++              goto error;
+       msleep(20);                             /* T2: > 10ms */
+       /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+       error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
+       if (error)
+-              return error;
++              goto error;
+       usleep_range(100, 2000);                /* T3: > 100us */
+       error = gpiod_direction_output(ts->gpiod_rst, 1);
+       if (error)
+-              return error;
++              goto error;
+       usleep_range(6000, 10000);              /* T4: > 5ms */
+       /* end select I2C slave addr */
+       error = gpiod_direction_input(ts->gpiod_rst);
+       if (error)
+-              return error;
++              goto error;
+-      error = goodix_int_sync(ts);
++      return 0;
++
++error:
++      dev_err(&ts->client->dev, "Controller reset failed.\n");
++      return error;
++}
++
++/**
++ * goodix_reset - Reset device during power on
++ *
++ * @ts: goodix_ts_data pointer
++ */
++static int goodix_reset(struct goodix_ts_data *ts)
++{
++      int error;
++
++      error = goodix_reset_no_int_sync(ts);
+       if (error)
+               return error;
+-      return 0;
++      return goodix_int_sync(ts);
+ }
+ #ifdef ACPI_GPIO_SUPPORT
+@@ -1144,10 +1164,8 @@ static int goodix_ts_probe(struct i2c_client *client,
+       if (ts->reset_controller_at_probe) {
+               /* reset the controller */
+               error = goodix_reset(ts);
+-              if (error) {
+-                      dev_err(&client->dev, "Controller reset failed.\n");
++              if (error)
+                       return error;
+-              }
+       }
+       error = goodix_i2c_test(client);
+@@ -1289,10 +1307,8 @@ static int __maybe_unused goodix_resume(struct device *dev)
+       if (error != 0 || config_ver != ts->config[0]) {
+               error = goodix_reset(ts);
+-              if (error) {
+-                      dev_err(dev, "Controller reset failed.\n");
++              if (error)
+                       return error;
+-              }
+               error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
+               if (error)
+diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
+index cdaced4f2980..0b88554ba2ae 100644
+--- a/drivers/input/touchscreen/goodix.h
++++ b/drivers/input/touchscreen/goodix.h
+@@ -69,5 +69,6 @@ int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len)
+ int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value);
+ int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len);
+ int goodix_int_sync(struct goodix_ts_data *ts);
++int goodix_reset_no_int_sync(struct goodix_ts_data *ts);
+ #endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch b/queue-5.15/input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch
new file mode 100644 (file)
index 0000000..4a075c1
--- /dev/null
@@ -0,0 +1,124 @@
+From 737dfb405e507718ae739d0bf348f289e32d77dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Dec 2021 23:15:09 -0800
+Subject: Input: goodix - try not to touch the reset-pin on x86/ACPI devices
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit a2fd46cd3dbb83b373ba74f4043f8dae869c65f1 ]
+
+Unless the controller is not responding at boot or after suspend/resume,
+the driver never resets the controller on x86/ACPI platforms. The driver
+still requesting the reset pin at probe() though in case it needs it.
+
+Until now the driver has always requested the reset pin with GPIOD_IN
+as type. The idea being to put the pin in high-impedance mode to save
+power until the driver actually wants to issue a reset.
+
+But this means that just requesting the pin can cause issues, since
+requesting it in another mode then GPIOD_ASIS may cause the pinctrl
+driver to touch the pin settings. We have already had issues before
+due to a bug in the pinctrl-cherryview.c driver which has been fixed in
+commit 921daeeca91b ("pinctrl: cherryview: Preserve
+CHV_PADCTRL1_INVRXTX_TXDATA flag on GPIOs").
+
+And now it turns out that requesting the reset-pin as GPIOD_IN also stops
+the touchscreen from working on the GPD P2 max mini-laptop. The behavior
+of putting the pin in high-impedance mode relies on there being some
+external pull-up to keep it high and there seems to be no pull-up on the
+GPD P2 max, causing things to break.
+
+This commit fixes this by requesting the reset pin as is when using
+the x86/ACPI code paths to lookup the GPIOs; and by not dropping it
+back into input-mode in case the driver does end up issuing a reset
+for error-recovery.
+
+BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=209061
+Fixes: a7d4b171660c ("Input: goodix - add support for getting IRQ + reset GPIOs on Cherry Trail devices")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20211206091116.44466-2-hdegoede@redhat.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/input/touchscreen/goodix.c | 30 +++++++++++++++++++++++++-----
+ drivers/input/touchscreen/goodix.h |  1 +
+ 2 files changed, 26 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
+index 2ca903a8af21..3667f7e51fde 100644
+--- a/drivers/input/touchscreen/goodix.c
++++ b/drivers/input/touchscreen/goodix.c
+@@ -640,10 +640,16 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
+       usleep_range(6000, 10000);              /* T4: > 5ms */
+-      /* end select I2C slave addr */
+-      error = gpiod_direction_input(ts->gpiod_rst);
+-      if (error)
+-              goto error;
++      /*
++       * Put the reset pin back in to input / high-impedance mode to save
++       * power. Only do this in the non ACPI case since some ACPI boards
++       * don't have a pull-up, so there the reset pin must stay active-high.
++       */
++      if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
++              error = gpiod_direction_input(ts->gpiod_rst);
++              if (error)
++                      goto error;
++      }
+       return 0;
+@@ -777,6 +783,14 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
+               return -EINVAL;
+       }
++      /*
++       * Normally we put the reset pin in input / high-impedance mode to save
++       * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
++       * case, leave the pin as is. This results in the pin not being touched
++       * at all on x86/ACPI boards, except when needed for error-recover.
++       */
++      ts->gpiod_rst_flags = GPIOD_ASIS;
++
+       return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
+ }
+ #else
+@@ -802,6 +816,12 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
+               return -EINVAL;
+       dev = &ts->client->dev;
++      /*
++       * By default we request the reset pin as input, leaving it in
++       * high-impedance when not resetting the controller to save power.
++       */
++      ts->gpiod_rst_flags = GPIOD_IN;
++
+       ts->avdd28 = devm_regulator_get(dev, "AVDD28");
+       if (IS_ERR(ts->avdd28)) {
+               error = PTR_ERR(ts->avdd28);
+@@ -839,7 +859,7 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
+       ts->gpiod_int = gpiod;
+       /* Get the reset line GPIO pin number */
+-      gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
++      gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
+       if (IS_ERR(gpiod)) {
+               error = PTR_ERR(gpiod);
+               if (error != -EPROBE_DEFER)
+diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
+index 0b88554ba2ae..1a1571ad2cd2 100644
+--- a/drivers/input/touchscreen/goodix.h
++++ b/drivers/input/touchscreen/goodix.h
+@@ -51,6 +51,7 @@ struct goodix_ts_data {
+       struct gpio_desc *gpiod_rst;
+       int gpio_count;
+       int gpio_int_idx;
++      enum gpiod_flags gpiod_rst_flags;
+       char id[GOODIX_ID_MAX_LEN + 1];
+       u16 version;
+       const char *cfg_name;
+-- 
+2.35.1
+
diff --git a/queue-5.15/io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch b/queue-5.15/io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch
new file mode 100644 (file)
index 0000000..d375efc
--- /dev/null
@@ -0,0 +1,40 @@
+From 24c560ad675bfcdd4ff3c5e4948716b40e953857 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 May 2022 11:24:56 +0100
+Subject: io_uring: avoid io-wq -EAGAIN looping for !IOPOLL
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit e0deb6a025ae8c850dc8685be39fb27b06c88736 ]
+
+If an opcode handler semi-reliably returns -EAGAIN, io_wq_submit_work()
+might continue busily hammer the same handler over and over again, which
+is not ideal. The -EAGAIN handling in question was put there only for
+IOPOLL, so restrict it to IOPOLL mode only where there is no other
+recourse than to retry as we cannot wait.
+
+Fixes: def596e9557c9 ("io_uring: support for IO polling")
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/f168b4f24181942f3614dd8ff648221736f572e6.1652433740.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/io_uring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index 0c5dcda0b622..9bff14c5e2b2 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -6866,7 +6866,7 @@ static void io_wq_submit_work(struct io_wq_work *work)
+                        * forcing a sync submission from here, since we can't
+                        * wait for request slots on the block side.
+                        */
+-                      if (ret != -EAGAIN)
++                      if (ret != -EAGAIN || !(req->ctx->flags & IORING_SETUP_IOPOLL))
+                               break;
+                       cond_resched();
+               } while (1);
+-- 
+2.35.1
+
diff --git a/queue-5.15/io_uring-ensure-that-fsnotify-is-always-called.patch b/queue-5.15/io_uring-ensure-that-fsnotify-is-always-called.patch
new file mode 100644 (file)
index 0000000..f46fbff
--- /dev/null
@@ -0,0 +1,52 @@
+From 51188a669f04cc25caf168d4544e9107dda827c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 20 Mar 2022 13:08:38 -0600
+Subject: io_uring: ensure that fsnotify is always called
+
+From: Jens Axboe <axboe@kernel.dk>
+
+[ Upstream commit f63cf5192fe3418ad5ae1a4412eba5694b145f79 ]
+
+Ensure that we call fsnotify_modify() if we write a file, and that we
+do fsnotify_access() if we read it. This enables anyone using inotify
+on the file to get notified.
+
+Ditto for fallocate, ensure that fsnotify_modify() is called.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/io_uring.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index 189323740324..0c5dcda0b622 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -2686,8 +2686,12 @@ static bool io_rw_should_reissue(struct io_kiocb *req)
+ static bool __io_complete_rw_common(struct io_kiocb *req, long res)
+ {
+-      if (req->rw.kiocb.ki_flags & IOCB_WRITE)
++      if (req->rw.kiocb.ki_flags & IOCB_WRITE) {
+               kiocb_end_write(req);
++              fsnotify_modify(req->file);
++      } else {
++              fsnotify_access(req->file);
++      }
+       if (res != req->result) {
+               if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
+                   io_rw_should_reissue(req)) {
+@@ -4183,6 +4187,8 @@ static int io_fallocate(struct io_kiocb *req, unsigned int issue_flags)
+                               req->sync.len);
+       if (ret < 0)
+               req_set_fail(req);
++      else
++              fsnotify_modify(req->file);
+       io_req_complete(req, ret);
+       return 0;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch b/queue-5.15/irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch
new file mode 100644 (file)
index 0000000..2ab6aad
--- /dev/null
@@ -0,0 +1,59 @@
+From 245f33562bcf9122b04ca6dc7b81cbbda44aa525 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 May 2022 14:30:36 +0100
+Subject: irqchip/gic-v3: Ensure pseudo-NMIs have an ISB between ack and
+ handling
+
+From: Mark Rutland <mark.rutland@arm.com>
+
+[ Upstream commit adf14453d2c037ab529040c1186ea32e277e783a ]
+
+There are cases where a context synchronization event is necessary
+between an IRQ being raised and being handled, and there are races such
+that we cannot rely upon the exception entry being subsequent to the
+interrupt being raised.
+
+We identified and fixes this for regular IRQs in commit:
+
+  39a06b67c2c1256b ("irqchip/gic: Ensure we have an ISB between ack and ->handle_irq")
+
+Unfortunately, we forgot to do the same for psuedo-NMIs when support for
+those was added in commit:
+
+  f32c926651dcd168 ("irqchip/gic-v3: Handle pseudo-NMIs")
+
+Which means that when pseudo-NMIs are used for PMU support, we'll hit
+the same problem.
+
+Apply the same fix as for regular IRQs. Note that when EOI mode 1 is in
+use, the call to gic_write_eoir() will provide an ISB.
+
+Fixes: f32c926651dcd168 ("irqchip/gic-v3: Handle pseudo-NMIs")
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20220513133038.226182-2-mark.rutland@arm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/irqchip/irq-gic-v3.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
+index fd4fb1b35787..d8ea330454f4 100644
+--- a/drivers/irqchip/irq-gic-v3.c
++++ b/drivers/irqchip/irq-gic-v3.c
+@@ -654,6 +654,9 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
+       if (static_branch_likely(&supports_deactivate_key))
+               gic_write_eoir(irqnr);
++      else
++              isb()
++
+       /*
+        * Leave the PSR.I bit set to prevent other NMIs to be
+        * received while handling this one.
+-- 
+2.35.1
+
diff --git a/queue-5.15/kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch b/queue-5.15/kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch
new file mode 100644 (file)
index 0000000..f81c3b6
--- /dev/null
@@ -0,0 +1,73 @@
+From 2985ca62cf7ef0744a894c07d95826db41667038 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Apr 2022 23:56:13 +0000
+Subject: KVM: Don't create VM debugfs files outside of the VM directory
+
+From: Oliver Upton <oupton@google.com>
+
+[ Upstream commit a44a4cc1c969afec97dbb2aedaf6f38eaa6253bb ]
+
+Unfortunately, there is no guarantee that KVM was able to instantiate a
+debugfs directory for a particular VM. To that end, KVM shouldn't even
+attempt to create new debugfs files in this case. If the specified
+parent dentry is NULL, debugfs_create_file() will instantiate files at
+the root of debugfs.
+
+For arm64, it is possible to create the vgic-state file outside of a
+VM directory, the file is not cleaned up when a VM is destroyed.
+Nonetheless, the corresponding struct kvm is freed when the VM is
+destroyed.
+
+Nip the problem in the bud for all possible errant debugfs file
+creations by initializing kvm->debugfs_dentry to -ENOENT. In so doing,
+debugfs_create_file() will fail instead of creating the file in the root
+directory.
+
+Cc: stable@kernel.org
+Fixes: 929f45e32499 ("kvm: no need to check return value of debugfs_create functions")
+Signed-off-by: Oliver Upton <oupton@google.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20220406235615.1447180-2-oupton@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ virt/kvm/kvm_main.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index 99c591569815..9134ae252d7c 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -911,7 +911,7 @@ static void kvm_destroy_vm_debugfs(struct kvm *kvm)
+       int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
+                                     kvm_vcpu_stats_header.num_desc;
+-      if (!kvm->debugfs_dentry)
++      if (IS_ERR(kvm->debugfs_dentry))
+               return;
+       debugfs_remove_recursive(kvm->debugfs_dentry);
+@@ -934,6 +934,12 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
+       int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
+                                     kvm_vcpu_stats_header.num_desc;
++      /*
++       * Force subsequent debugfs file creations to fail if the VM directory
++       * is not created.
++       */
++      kvm->debugfs_dentry = ERR_PTR(-ENOENT);
++
+       if (!debugfs_initialized())
+               return 0;
+@@ -5373,7 +5379,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
+       }
+       add_uevent_var(env, "PID=%d", kvm->userspace_pid);
+-      if (kvm->debugfs_dentry) {
++      if (!IS_ERR(kvm->debugfs_dentry)) {
+               char *tmp, *p = kmalloc(PATH_MAX, GFP_KERNEL_ACCOUNT);
+               if (p) {
+-- 
+2.35.1
+
diff --git a/queue-5.15/kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch b/queue-5.15/kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch
new file mode 100644 (file)
index 0000000..8dd1b00
--- /dev/null
@@ -0,0 +1,83 @@
+From 4f13ab50660d60629e63fbb603c25f1a6c9a1427 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Apr 2022 00:46:22 +0000
+Subject: KVM: Initialize debugfs_dentry when a VM is created to avoid NULL
+ deref
+
+From: Sean Christopherson <seanjc@google.com>
+
+[ Upstream commit 5c697c367a66307a5d943c3449421aff2aa3ca4a ]
+
+Initialize debugfs_entry to its semi-magical -ENOENT value when the VM
+is created.  KVM's teardown when VM creation fails is kludgy and calls
+kvm_uevent_notify_change() and kvm_destroy_vm_debugfs() even if KVM never
+attempted kvm_create_vm_debugfs().  Because debugfs_entry is zero
+initialized, the IS_ERR() checks pass and KVM derefs a NULL pointer.
+
+  BUG: kernel NULL pointer dereference, address: 0000000000000018
+  #PF: supervisor read access in kernel mode
+  #PF: error_code(0x0000) - not-present page
+  PGD 1068b1067 P4D 1068b1067 PUD 1068b0067 PMD 0
+  Oops: 0000 [#1] SMP
+  CPU: 0 PID: 871 Comm: repro Not tainted 5.18.0-rc1+ #825
+  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
+  RIP: 0010:__dentry_path+0x7b/0x130
+  Call Trace:
+   <TASK>
+   dentry_path_raw+0x42/0x70
+   kvm_uevent_notify_change.part.0+0x10c/0x200 [kvm]
+   kvm_put_kvm+0x63/0x2b0 [kvm]
+   kvm_dev_ioctl+0x43a/0x920 [kvm]
+   __x64_sys_ioctl+0x83/0xb0
+   do_syscall_64+0x31/0x50
+   entry_SYSCALL_64_after_hwframe+0x44/0xae
+   </TASK>
+  Modules linked in: kvm_intel kvm irqbypass
+
+Fixes: a44a4cc1c969 ("KVM: Don't create VM debugfs files outside of the VM directory")
+Cc: stable@vger.kernel.org
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Oliver Upton <oupton@google.com>
+Reported-by: syzbot+df6fbbd2ee39f21289ef@syzkaller.appspotmail.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Reviewed-by: Oliver Upton <oupton@google.com>
+Message-Id: <20220415004622.2207751-1-seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ virt/kvm/kvm_main.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index 9134ae252d7c..9eac68ae291e 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -934,12 +934,6 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
+       int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
+                                     kvm_vcpu_stats_header.num_desc;
+-      /*
+-       * Force subsequent debugfs file creations to fail if the VM directory
+-       * is not created.
+-       */
+-      kvm->debugfs_dentry = ERR_PTR(-ENOENT);
+-
+       if (!debugfs_initialized())
+               return 0;
+@@ -1055,6 +1049,12 @@ static struct kvm *kvm_create_vm(unsigned long type)
+       BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
++      /*
++       * Force subsequent debugfs file creations to fail if the VM directory
++       * is not created (by kvm_create_vm_debugfs()).
++       */
++      kvm->debugfs_dentry = ERR_PTR(-ENOENT);
++
+       if (init_srcu_struct(&kvm->srcu))
+               goto out_err_no_srcu;
+       if (init_srcu_struct(&kvm->irq_srcu))
+-- 
+2.35.1
+
diff --git a/queue-5.15/kvm-s390x-fix-sck-locking.patch b/queue-5.15/kvm-s390x-fix-sck-locking.patch
new file mode 100644 (file)
index 0000000..7fd207e
--- /dev/null
@@ -0,0 +1,135 @@
+From 61debb18b5c11bf52e37e7e2c62468b44a3cdbcd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Mar 2022 15:33:40 +0100
+Subject: KVM: s390x: fix SCK locking
+
+From: Claudio Imbrenda <imbrenda@linux.ibm.com>
+
+[ Upstream commit c0573ba5c5a2244dc02060b1f374d4593c1d20b7 ]
+
+When handling the SCK instruction, the kvm lock is taken, even though
+the vcpu lock is already being held. The normal locking order is kvm
+lock first and then vcpu lock. This is can (and in some circumstances
+does) lead to deadlocks.
+
+The function kvm_s390_set_tod_clock is called both by the SCK handler
+and by some IOCTLs to set the clock. The IOCTLs will not hold the vcpu
+lock, so they can safely take the kvm lock. The SCK handler holds the
+vcpu lock, but will also somehow need to acquire the kvm lock without
+relinquishing the vcpu lock.
+
+The solution is to factor out the code to set the clock, and provide
+two wrappers. One is called like the original function and does the
+locking, the other is called kvm_s390_try_set_tod_clock and uses
+trylock to try to acquire the kvm lock. This new wrapper is then used
+in the SCK handler. If locking fails, -EAGAIN is returned, which is
+eventually propagated to userspace, thus also freeing the vcpu lock and
+allowing for forward progress.
+
+This is not the most efficient or elegant way to solve this issue, but
+the SCK instruction is deprecated and its performance is not critical.
+
+The goal of this patch is just to provide a simple but correct way to
+fix the bug.
+
+Fixes: 6a3f95a6b04c ("KVM: s390: Intercept SCK instruction")
+Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
+Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Reviewed-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
+Link: https://lore.kernel.org/r/20220301143340.111129-1-imbrenda@linux.ibm.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kvm/kvm-s390.c | 19 ++++++++++++++++---
+ arch/s390/kvm/kvm-s390.h |  4 ++--
+ arch/s390/kvm/priv.c     | 15 ++++++++++++++-
+ 3 files changed, 32 insertions(+), 6 deletions(-)
+
+diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
+index 402597f9d050..b456aa196c04 100644
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -3913,14 +3913,12 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
+       return 0;
+ }
+-void kvm_s390_set_tod_clock(struct kvm *kvm,
+-                          const struct kvm_s390_vm_tod_clock *gtod)
++static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
+ {
+       struct kvm_vcpu *vcpu;
+       union tod_clock clk;
+       int i;
+-      mutex_lock(&kvm->lock);
+       preempt_disable();
+       store_tod_clock_ext(&clk);
+@@ -3941,7 +3939,22 @@ void kvm_s390_set_tod_clock(struct kvm *kvm,
+       kvm_s390_vcpu_unblock_all(kvm);
+       preempt_enable();
++}
++
++void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
++{
++      mutex_lock(&kvm->lock);
++      __kvm_s390_set_tod_clock(kvm, gtod);
++      mutex_unlock(&kvm->lock);
++}
++
++int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
++{
++      if (!mutex_trylock(&kvm->lock))
++              return 0;
++      __kvm_s390_set_tod_clock(kvm, gtod);
+       mutex_unlock(&kvm->lock);
++      return 1;
+ }
+ /**
+diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
+index 1539dd981104..f8803bf0ff17 100644
+--- a/arch/s390/kvm/kvm-s390.h
++++ b/arch/s390/kvm/kvm-s390.h
+@@ -326,8 +326,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
+ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
+ /* implemented in kvm-s390.c */
+-void kvm_s390_set_tod_clock(struct kvm *kvm,
+-                          const struct kvm_s390_vm_tod_clock *gtod);
++void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
++int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
+ long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
+ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
+ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
+diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
+index 417154b314a6..6a765fe22eaf 100644
+--- a/arch/s390/kvm/priv.c
++++ b/arch/s390/kvm/priv.c
+@@ -102,7 +102,20 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
+               return kvm_s390_inject_prog_cond(vcpu, rc);
+       VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
+-      kvm_s390_set_tod_clock(vcpu->kvm, &gtod);
++      /*
++       * To set the TOD clock the kvm lock must be taken, but the vcpu lock
++       * is already held in handle_set_clock. The usual lock order is the
++       * opposite.  As SCK is deprecated and should not be used in several
++       * cases, for example when the multiple epoch facility or TOD clock
++       * steering facility is installed (see Principles of Operation),  a
++       * slow path can be used.  If the lock can not be taken via try_lock,
++       * the instruction will be retried via -EAGAIN at a later point in
++       * time.
++       */
++      if (!kvm_s390_try_set_tod_clock(vcpu->kvm, &gtod)) {
++              kvm_s390_retry_instr(vcpu);
++              return -EAGAIN;
++      }
+       kvm_s390_set_psw_cc(vcpu, 0);
+       return 0;
+-- 
+2.35.1
+
diff --git a/queue-5.15/kvm-use-__vcalloc-for-very-large-allocations.patch b/queue-5.15/kvm-use-__vcalloc-for-very-large-allocations.patch
new file mode 100644 (file)
index 0000000..b8f1cb1
--- /dev/null
@@ -0,0 +1,94 @@
+From 7d144e57875e6e10e3e93bf63061f0761191419d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Mar 2022 04:49:37 -0500
+Subject: KVM: use __vcalloc for very large allocations
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+[ Upstream commit 37b2a6510a48ca361ced679f92682b7b7d7d0330 ]
+
+Allocations whose size is related to the memslot size can be arbitrarily
+large.  Do not use kvzalloc/kvcalloc, as those are limited to "not crazy"
+sizes that fit in 32 bits.
+
+Cc: stable@vger.kernel.org
+Fixes: 7661809d493b ("mm: don't allow oversized kvmalloc() calls")
+Reviewed-by: David Hildenbrand <david@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/kvm/book3s_hv_uvmem.c | 2 +-
+ arch/x86/kvm/mmu/page_track.c      | 4 ++--
+ arch/x86/kvm/x86.c                 | 4 ++--
+ virt/kvm/kvm_main.c                | 4 ++--
+ 4 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c
+index 3fbe710ff839..3d4ee75b0fb7 100644
+--- a/arch/powerpc/kvm/book3s_hv_uvmem.c
++++ b/arch/powerpc/kvm/book3s_hv_uvmem.c
+@@ -251,7 +251,7 @@ int kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot)
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+-      p->pfns = vzalloc(array_size(slot->npages, sizeof(*p->pfns)));
++      p->pfns = vcalloc(slot->npages, sizeof(*p->pfns));
+       if (!p->pfns) {
+               kfree(p);
+               return -ENOMEM;
+diff --git a/arch/x86/kvm/mmu/page_track.c b/arch/x86/kvm/mmu/page_track.c
+index 21427e84a82e..630ae70bb6bd 100644
+--- a/arch/x86/kvm/mmu/page_track.c
++++ b/arch/x86/kvm/mmu/page_track.c
+@@ -36,8 +36,8 @@ int kvm_page_track_create_memslot(struct kvm_memory_slot *slot,
+       for (i = 0; i < KVM_PAGE_TRACK_MAX; i++) {
+               slot->arch.gfn_track[i] =
+-                      kvcalloc(npages, sizeof(*slot->arch.gfn_track[i]),
+-                               GFP_KERNEL_ACCOUNT);
++                      __vcalloc(npages, sizeof(*slot->arch.gfn_track[i]),
++                                GFP_KERNEL_ACCOUNT);
+               if (!slot->arch.gfn_track[i])
+                       goto track_free;
+       }
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index 39aaa21e28f7..8974884ef2ad 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -11552,7 +11552,7 @@ static int memslot_rmap_alloc(struct kvm_memory_slot *slot,
+               if (slot->arch.rmap[i])
+                       continue;
+-              slot->arch.rmap[i] = kvcalloc(lpages, sz, GFP_KERNEL_ACCOUNT);
++              slot->arch.rmap[i] = __vcalloc(lpages, sz, GFP_KERNEL_ACCOUNT);
+               if (!slot->arch.rmap[i]) {
+                       memslot_rmap_free(slot);
+                       return -ENOMEM;
+@@ -11633,7 +11633,7 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm,
+               lpages = __kvm_mmu_slot_lpages(slot, npages, level);
+-              linfo = kvcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT);
++              linfo = __vcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT);
+               if (!linfo)
+                       goto out_free;
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index fefdf3a6dae3..99c591569815 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -1255,9 +1255,9 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
+  */
+ static int kvm_alloc_dirty_bitmap(struct kvm_memory_slot *memslot)
+ {
+-      unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot);
++      unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot);
+-      memslot->dirty_bitmap = kvzalloc(dirty_bytes, GFP_KERNEL_ACCOUNT);
++      memslot->dirty_bitmap = __vcalloc(2, dirty_bytes, GFP_KERNEL_ACCOUNT);
+       if (!memslot->dirty_bitmap)
+               return -ENOMEM;
+-- 
+2.35.1
+
diff --git a/queue-5.15/kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch b/queue-5.15/kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch
new file mode 100644 (file)
index 0000000..67bec90
--- /dev/null
@@ -0,0 +1,50 @@
+From 0a25179387b96a566e3b371ef59279f1ea916809 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Dec 2021 01:15:54 +0000
+Subject: KVM: x86/mmu: Use common TDP MMU zap helper for MMU notifier unmap
+ hook
+
+From: Sean Christopherson <seanjc@google.com>
+
+[ Upstream commit 83b83a02073ec8d18c77a9bbe0881d710f7a9d32 ]
+
+Use the common TDP MMU zap helper when handling an MMU notifier unmap
+event, the two flows are semantically identical.  Consolidate the code in
+preparation for a future bug fix, as both kvm_tdp_mmu_unmap_gfn_range()
+and __kvm_tdp_mmu_zap_gfn_range() are guilty of not zapping SPTEs in
+invalid roots.
+
+No functional change intended.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Message-Id: <20211215011557.399940-2-seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kvm/mmu/tdp_mmu.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
+index 6195f0d219ae..6c2bb60ccd88 100644
+--- a/arch/x86/kvm/mmu/tdp_mmu.c
++++ b/arch/x86/kvm/mmu/tdp_mmu.c
+@@ -1098,13 +1098,8 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
+ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range,
+                                bool flush)
+ {
+-      struct kvm_mmu_page *root;
+-
+-      for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false)
+-              flush = zap_gfn_range(kvm, root, range->start, range->end,
+-                                    range->may_block, flush, false);
+-
+-      return flush;
++      return __kvm_tdp_mmu_zap_gfn_range(kvm, range->slot->as_id, range->start,
++                                         range->end, range->may_block, flush);
+ }
+ typedef bool (*tdp_handler_t)(struct kvm *kvm, struct tdp_iter *iter,
+-- 
+2.35.1
+
diff --git a/queue-5.15/kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch b/queue-5.15/kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch
new file mode 100644 (file)
index 0000000..047bf7a
--- /dev/null
@@ -0,0 +1,40 @@
+From b6d49e59a28b2f32843078a88e9867be0f4d4539 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Nov 2021 01:50:08 +0000
+Subject: KVM: x86/mmu: Use yield-safe TDP MMU root iter in MMU notifier
+ unmapping
+
+From: Sean Christopherson <seanjc@google.com>
+
+[ Upstream commit 7533377215b6ee432c06c5855f6be5d66e694e46 ]
+
+Use the yield-safe variant of the TDP MMU iterator when handling an
+unmapping event from the MMU notifier, as most occurences of the event
+allow yielding.
+
+Fixes: e1eed5847b09 ("KVM: x86/mmu: Allow yielding during MMU notifier unmap/zap, if possible")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Message-Id: <20211120015008.3780032-1-seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kvm/mmu/tdp_mmu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
+index 853780eb033b..6195f0d219ae 100644
+--- a/arch/x86/kvm/mmu/tdp_mmu.c
++++ b/arch/x86/kvm/mmu/tdp_mmu.c
+@@ -1100,7 +1100,7 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range,
+ {
+       struct kvm_mmu_page *root;
+-      for_each_tdp_mmu_root(kvm, root, range->slot->as_id)
++      for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false)
+               flush = zap_gfn_range(kvm, root, range->start, range->end,
+                                     range->may_block, flush, false);
+-- 
+2.35.1
+
diff --git a/queue-5.15/media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch b/queue-5.15/media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch
new file mode 100644 (file)
index 0000000..840a5dc
--- /dev/null
@@ -0,0 +1,189 @@
+From e5374a0d2e9679bb6d597bf0c47508d5b2316665 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Dec 2021 15:20:24 +0100
+Subject: media: davinci: vpif: fix use-after-free on driver unbind
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit 43acb728bbc40169d2e2425e84a80068270974be ]
+
+The driver allocates and registers two platform device structures during
+probe, but the devices were never deregistered on driver unbind.
+
+This results in a use-after-free on driver unbind as the device
+structures were allocated using devres and would be freed by driver
+core when remove() returns.
+
+Fix this by adding the missing deregistration calls to the remove()
+callback and failing probe on registration errors.
+
+Note that the platform device structures must be freed using a proper
+release callback to avoid leaking associated resources like device
+names.
+
+Fixes: 479f7a118105 ("[media] davinci: vpif: adaptions for DT support")
+Cc: stable@vger.kernel.org      # 4.12
+Cc: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Reviewed-by: Lad Prabhakar <prabhakar.csengg@gmail.com>
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/davinci/vpif.c | 97 ++++++++++++++++++++-------
+ 1 file changed, 71 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
+index 5658c7f148d7..8ffc01c606d0 100644
+--- a/drivers/media/platform/davinci/vpif.c
++++ b/drivers/media/platform/davinci/vpif.c
+@@ -41,6 +41,11 @@ MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
+ #define VPIF_CH2_MAX_MODES    15
+ #define VPIF_CH3_MAX_MODES    2
++struct vpif_data {
++      struct platform_device *capture;
++      struct platform_device *display;
++};
++
+ DEFINE_SPINLOCK(vpif_lock);
+ EXPORT_SYMBOL_GPL(vpif_lock);
+@@ -423,11 +428,19 @@ int vpif_channel_getfid(u8 channel_id)
+ }
+ EXPORT_SYMBOL(vpif_channel_getfid);
++static void vpif_pdev_release(struct device *dev)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++
++      kfree(pdev);
++}
++
+ static int vpif_probe(struct platform_device *pdev)
+ {
+       static struct resource  *res, *res_irq;
+       struct platform_device *pdev_capture, *pdev_display;
+       struct device_node *endpoint = NULL;
++      struct vpif_data *data;
+       int ret;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -435,6 +448,12 @@ static int vpif_probe(struct platform_device *pdev)
+       if (IS_ERR(vpif_base))
+               return PTR_ERR(vpif_base);
++      data = kzalloc(sizeof(*data), GFP_KERNEL);
++      if (!data)
++              return -ENOMEM;
++
++      platform_set_drvdata(pdev, data);
++
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get(&pdev->dev);
+@@ -462,49 +481,75 @@ static int vpif_probe(struct platform_device *pdev)
+               goto err_put_rpm;
+       }
+-      pdev_capture = devm_kzalloc(&pdev->dev, sizeof(*pdev_capture),
+-                                  GFP_KERNEL);
+-      if (pdev_capture) {
+-              pdev_capture->name = "vpif_capture";
+-              pdev_capture->id = -1;
+-              pdev_capture->resource = res_irq;
+-              pdev_capture->num_resources = 1;
+-              pdev_capture->dev.dma_mask = pdev->dev.dma_mask;
+-              pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
+-              pdev_capture->dev.parent = &pdev->dev;
+-              platform_device_register(pdev_capture);
+-      } else {
+-              dev_warn(&pdev->dev, "Unable to allocate memory for pdev_capture.\n");
++      pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL);
++      if (!pdev_capture) {
++              ret = -ENOMEM;
++              goto err_put_rpm;
+       }
+-      pdev_display = devm_kzalloc(&pdev->dev, sizeof(*pdev_display),
+-                                  GFP_KERNEL);
+-      if (pdev_display) {
+-              pdev_display->name = "vpif_display";
+-              pdev_display->id = -1;
+-              pdev_display->resource = res_irq;
+-              pdev_display->num_resources = 1;
+-              pdev_display->dev.dma_mask = pdev->dev.dma_mask;
+-              pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
+-              pdev_display->dev.parent = &pdev->dev;
+-              platform_device_register(pdev_display);
+-      } else {
+-              dev_warn(&pdev->dev, "Unable to allocate memory for pdev_display.\n");
++      pdev_capture->name = "vpif_capture";
++      pdev_capture->id = -1;
++      pdev_capture->resource = res_irq;
++      pdev_capture->num_resources = 1;
++      pdev_capture->dev.dma_mask = pdev->dev.dma_mask;
++      pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
++      pdev_capture->dev.parent = &pdev->dev;
++      pdev_capture->dev.release = vpif_pdev_release;
++
++      ret = platform_device_register(pdev_capture);
++      if (ret)
++              goto err_put_pdev_capture;
++
++      pdev_display = kzalloc(sizeof(*pdev_display), GFP_KERNEL);
++      if (!pdev_display) {
++              ret = -ENOMEM;
++              goto err_put_pdev_capture;
+       }
++      pdev_display->name = "vpif_display";
++      pdev_display->id = -1;
++      pdev_display->resource = res_irq;
++      pdev_display->num_resources = 1;
++      pdev_display->dev.dma_mask = pdev->dev.dma_mask;
++      pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
++      pdev_display->dev.parent = &pdev->dev;
++      pdev_display->dev.release = vpif_pdev_release;
++
++      ret = platform_device_register(pdev_display);
++      if (ret)
++              goto err_put_pdev_display;
++
++      data->capture = pdev_capture;
++      data->display = pdev_display;
++
+       return 0;
++err_put_pdev_display:
++      platform_device_put(pdev_display);
++err_put_pdev_capture:
++      platform_device_put(pdev_capture);
+ err_put_rpm:
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
++      kfree(data);
+       return ret;
+ }
+ static int vpif_remove(struct platform_device *pdev)
+ {
++      struct vpif_data *data = platform_get_drvdata(pdev);
++
++      if (data->capture)
++              platform_device_unregister(data->capture);
++      if (data->display)
++              platform_device_unregister(data->display);
++
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
++
++      kfree(data);
++
+       return 0;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/media-ir_toy-prevent-device-from-hanging-during-tran.patch b/queue-5.15/media-ir_toy-prevent-device-from-hanging-during-tran.patch
new file mode 100644 (file)
index 0000000..67813f3
--- /dev/null
@@ -0,0 +1,40 @@
+From 98157c283c583fd9fcb7974e6fe4167a57dc0567 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Sep 2021 16:57:46 +0200
+Subject: media: ir_toy: prevent device from hanging during transmit
+
+From: Sean Young <sean@mess.org>
+
+[ Upstream commit 4114978dcd24e72415276bba60ff4ff355970bbc ]
+
+If the IR Toy is receiving IR while a transmit is done, it may end up
+hanging. We can prevent this from happening by re-entering sample mode
+just before issuing the transmit command.
+
+Link: https://github.com/bengtmartensson/HarcHardware/discussions/25
+
+Cc: stable@vger.kernel.org
+[mchehab: renamed: s/STATE_RESET/STATE_COMMAND_NO_RESP/ ]
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/rc/ir_toy.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c
+index 7f394277478b..53ae19fa103a 100644
+--- a/drivers/media/rc/ir_toy.c
++++ b/drivers/media/rc/ir_toy.c
+@@ -310,7 +310,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)
+               buf[i] = cpu_to_be16(v);
+       }
+-      buf[count] = cpu_to_be16(0xffff);
++      buf[count] = 0xffff;
+       irtoy->tx_buf = buf;
+       irtoy->tx_len = size;
+-- 
+2.35.1
+
diff --git a/queue-5.15/media-omap3isp-use-struct_group-for-memcpy-region.patch b/queue-5.15/media-omap3isp-use-struct_group-for-memcpy-region.patch
new file mode 100644 (file)
index 0000000..9bcdb15
--- /dev/null
@@ -0,0 +1,135 @@
+From a3911f90c150b423ab9bcf36e172f507f8765853 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Jan 2022 18:29:52 +0100
+Subject: media: omap3isp: Use struct_group() for memcpy() region
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit d4568fc8525897e683983806f813be1ae9eedaed ]
+
+In preparation for FORTIFY_SOURCE performing compile-time and run-time
+field bounds checking for memcpy(), memmove(), and memset(), avoid
+intentionally writing across neighboring fields. Wrap the target region
+in struct_group(). This additionally fixes a theoretical misalignment
+of the copy (since the size of "buf" changes between 64-bit and 32-bit,
+but this is likely never built for 64-bit).
+
+FWIW, I think this code is totally broken on 64-bit (which appears to
+not be a "real" build configuration): it would either always fail (with
+an uninitialized data->buf_size) or would cause corruption in userspace
+due to the copy_to_user() in the call path against an uninitialized
+data->buf value:
+
+omap3isp_stat_request_statistics_time32(...)
+    struct omap3isp_stat_data data64;
+    ...
+    omap3isp_stat_request_statistics(stat, &data64);
+
+int omap3isp_stat_request_statistics(struct ispstat *stat,
+                                     struct omap3isp_stat_data *data)
+    ...
+    buf = isp_stat_buf_get(stat, data);
+
+static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat,
+                                               struct omap3isp_stat_data *data)
+...
+    if (buf->buf_size > data->buf_size) {
+            ...
+            return ERR_PTR(-EINVAL);
+    }
+    ...
+    rval = copy_to_user(data->buf,
+                        buf->virt_addr,
+                        buf->buf_size);
+
+Regardless, additionally initialize data64 to be zero-filled to avoid
+undefined behavior.
+
+Link: https://lore.kernel.org/lkml/20211215220505.GB21862@embeddedor
+
+Cc: Arnd Bergmann <arnd@arndb.de>
+Fixes: 378e3f81cb56 ("media: omap3isp: support 64-bit version of omap3isp_stat_data")
+Cc: stable@vger.kernel.org
+Reviewed-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/omap3isp/ispstat.c |  5 +++--
+ include/uapi/linux/omap3isp.h             | 21 +++++++++++++--------
+ 2 files changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
+index 5b9b57f4d9bf..68cf68dbcace 100644
+--- a/drivers/media/platform/omap3isp/ispstat.c
++++ b/drivers/media/platform/omap3isp/ispstat.c
+@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,
+ int omap3isp_stat_request_statistics_time32(struct ispstat *stat,
+                                       struct omap3isp_stat_data_time32 *data)
+ {
+-      struct omap3isp_stat_data data64;
++      struct omap3isp_stat_data data64 = { };
+       int ret;
+       ret = omap3isp_stat_request_statistics(stat, &data64);
+@@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct ispstat *stat,
+       data->ts.tv_sec = data64.ts.tv_sec;
+       data->ts.tv_usec = data64.ts.tv_usec;
+-      memcpy(&data->buf, &data64.buf, sizeof(*data) - sizeof(data->ts));
++      data->buf = (uintptr_t)data64.buf;
++      memcpy(&data->frame, &data64.frame, sizeof(data->frame));
+       return 0;
+ }
+diff --git a/include/uapi/linux/omap3isp.h b/include/uapi/linux/omap3isp.h
+index 87b55755f4ff..d9db7ad43890 100644
+--- a/include/uapi/linux/omap3isp.h
++++ b/include/uapi/linux/omap3isp.h
+@@ -162,6 +162,7 @@ struct omap3isp_h3a_aewb_config {
+  * struct omap3isp_stat_data - Statistic data sent to or received from user
+  * @ts: Timestamp of returned framestats.
+  * @buf: Pointer to pass to user.
++ * @buf_size: Size of buffer.
+  * @frame_number: Frame number of requested stats.
+  * @cur_frame: Current frame number being processed.
+  * @config_counter: Number of the configuration associated with the data.
+@@ -176,10 +177,12 @@ struct omap3isp_stat_data {
+       struct timeval ts;
+ #endif
+       void __user *buf;
+-      __u32 buf_size;
+-      __u16 frame_number;
+-      __u16 cur_frame;
+-      __u16 config_counter;
++      __struct_group(/* no tag */, frame, /* no attrs */,
++              __u32 buf_size;
++              __u16 frame_number;
++              __u16 cur_frame;
++              __u16 config_counter;
++      );
+ };
+ #ifdef __KERNEL__
+@@ -189,10 +192,12 @@ struct omap3isp_stat_data_time32 {
+               __s32   tv_usec;
+       } ts;
+       __u32 buf;
+-      __u32 buf_size;
+-      __u16 frame_number;
+-      __u16 cur_frame;
+-      __u16 config_counter;
++      __struct_group(/* no tag */, frame, /* no attrs */,
++              __u32 buf_size;
++              __u16 frame_number;
++              __u16 cur_frame;
++              __u16 config_counter;
++      );
+ };
+ #endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch b/queue-5.15/memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch
new file mode 100644 (file)
index 0000000..4000954
--- /dev/null
@@ -0,0 +1,130 @@
+From df654f0afe33c08afd50534b9891e6e08f596a0a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Sep 2021 13:48:30 -0500
+Subject: memory: renesas-rpc-if: Avoid unaligned bus access for HyperFlash
+
+From: Andrew Gabbasov <andrew_gabbasov@mentor.com>
+
+[ Upstream commit 1869023e24c0de73a160a424dac4621cefd628ae ]
+
+HyperFlash devices in Renesas SoCs use 2-bytes addressing, according
+to HW manual paragraph 62.3.3 (which officially describes Serial Flash
+access, but seems to be applicable to HyperFlash too). And 1-byte bus
+read operations to 2-bytes unaligned addresses in external address space
+read mode work incorrectly (returns the other byte from the same word).
+
+Function memcpy_fromio(), used by the driver to read data from the bus,
+in ARM64 architecture (to which Renesas cores belong) uses 8-bytes
+bus accesses for appropriate aligned addresses, and 1-bytes accesses
+for other addresses. This results in incorrect data read from HyperFlash
+in unaligned cases.
+
+This issue can be reproduced using something like the following commands
+(where mtd1 is a parition on Hyperflash storage, defined properly
+in a device tree):
+
+[Correct fragment, read from Hyperflash]
+
+    root@rcar-gen3:~# dd if=/dev/mtd1 of=/tmp/zz bs=32 count=1
+    root@rcar-gen3:~# hexdump -C /tmp/zz
+    00000000  f4 03 00 aa f5 03 01 aa  f6 03 02 aa f7 03 03 aa  |................|
+    00000010  00 00 80 d2 40 20 18 d5  00 06 81 d2 a0 18 a6 f2  |....@ ..........|
+    00000020
+
+[Incorrect read of the same fragment: see the difference at offsets 8-11]
+
+    root@rcar-gen3:~# dd if=/dev/mtd1 of=/tmp/zz bs=12 count=1
+    root@rcar-gen3:~# hexdump -C /tmp/zz
+    00000000  f4 03 00 aa f5 03 01 aa  03 03 aa aa              |............|
+    0000000c
+
+Fix this issue by creating a local replacement of the copying function,
+that performs only properly aligned bus accesses, and is used for reading
+from HyperFlash.
+
+Fixes: ca7d8b980b67f ("memory: add Renesas RPC-IF driver")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Gabbasov <andrew_gabbasov@mentor.com>
+Link: https://lore.kernel.org/r/20210922184830.29147-1-andrew_gabbasov@mentor.com
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/memory/renesas-rpc-if.c | 48 +++++++++++++++++++++++++++++++--
+ 1 file changed, 46 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
+index 3a416705f61c..c77b23b68a93 100644
+--- a/drivers/memory/renesas-rpc-if.c
++++ b/drivers/memory/renesas-rpc-if.c
+@@ -199,7 +199,6 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
+       *val = readl(rpc->base + reg);
+       return 0;
+-
+ }
+ static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
+@@ -577,6 +576,48 @@ int rpcif_manual_xfer(struct rpcif *rpc)
+ }
+ EXPORT_SYMBOL(rpcif_manual_xfer);
++static void memcpy_fromio_readw(void *to,
++                              const void __iomem *from,
++                              size_t count)
++{
++      const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4;
++      u8 buf[2];
++
++      if (count && ((unsigned long)from & 1)) {
++              *(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1));
++              *(u8 *)to = buf[1];
++              from++;
++              to++;
++              count--;
++      }
++      while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) {
++              *(u16 *)to = __raw_readw(from);
++              from += 2;
++              to += 2;
++              count -= 2;
++      }
++      while (count >= maxw) {
++#ifdef CONFIG_64BIT
++              *(u64 *)to = __raw_readq(from);
++#else
++              *(u32 *)to = __raw_readl(from);
++#endif
++              from += maxw;
++              to += maxw;
++              count -= maxw;
++      }
++      while (count >= 2) {
++              *(u16 *)to = __raw_readw(from);
++              from += 2;
++              to += 2;
++              count -= 2;
++      }
++      if (count) {
++              *(u16 *)buf = __raw_readw(from);
++              *(u8 *)to = buf[0];
++      }
++}
++
+ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
+ {
+       loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1);
+@@ -598,7 +639,10 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
+       regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy);
+       regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr);
+-      memcpy_fromio(buf, rpc->dirmap + from, len);
++      if (rpc->bus_size == 2)
++              memcpy_fromio_readw(buf, rpc->dirmap + from, len);
++      else
++              memcpy_fromio(buf, rpc->dirmap + from, len);
+       pm_runtime_put(rpc->dev);
+-- 
+2.35.1
+
diff --git a/queue-5.15/mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch b/queue-5.15/mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch
new file mode 100644 (file)
index 0000000..4bd3ff6
--- /dev/null
@@ -0,0 +1,145 @@
+From 2dfee9660b82b297bc639c30ea574745465511cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Mar 2022 14:44:38 -0700
+Subject: mm/hwpoison: avoid the impact of hwpoison_filter() return value on
+ mce handler
+
+From: luofei <luofei@unicloud.com>
+
+[ Upstream commit d1fe111fb62a1cf0446a2919f5effbb33ad0702c ]
+
+When the hwpoison page meets the filter conditions, it should not be
+regarded as successful memory_failure() processing for mce handler, but
+should return a distinct value, otherwise mce handler regards the error
+page has been identified and isolated, which may lead to calling
+set_mce_nospec() to change page attribute, etc.
+
+Here memory_failure() return -EOPNOTSUPP to indicate that the error
+event is filtered, mce handler should not take any action for this
+situation and hwpoison injector should treat as correct.
+
+Link: https://lkml.kernel.org/r/20220223082135.2769649-1-luofei@unicloud.com
+Signed-off-by: luofei <luofei@unicloud.com>
+Acked-by: Borislav Petkov <bp@suse.de>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: H. Peter Anvin <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Naoya Horiguchi <naoya.horiguchi@nec.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/mce/core.c | 8 +++++---
+ drivers/base/memory.c          | 2 ++
+ mm/hwpoison-inject.c           | 3 ++-
+ mm/madvise.c                   | 2 ++
+ mm/memory-failure.c            | 9 +++++++--
+ 5 files changed, 18 insertions(+), 6 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
+index e23e74e2f928..848cfb013f58 100644
+--- a/arch/x86/kernel/cpu/mce/core.c
++++ b/arch/x86/kernel/cpu/mce/core.c
+@@ -1297,10 +1297,12 @@ static void kill_me_maybe(struct callback_head *cb)
+       /*
+        * -EHWPOISON from memory_failure() means that it already sent SIGBUS
+-       * to the current process with the proper error info, so no need to
+-       * send SIGBUS here again.
++       * to the current process with the proper error info,
++       * -EOPNOTSUPP means hwpoison_filter() filtered the error event,
++       *
++       * In both cases, no further processing is required.
+        */
+-      if (ret == -EHWPOISON)
++      if (ret == -EHWPOISON || ret == -EOPNOTSUPP)
+               return;
+       if (p->mce_vaddr != (void __user *)-1l) {
+diff --git a/drivers/base/memory.c b/drivers/base/memory.c
+index c0d501a3a714..c778d1df7455 100644
+--- a/drivers/base/memory.c
++++ b/drivers/base/memory.c
+@@ -555,6 +555,8 @@ static ssize_t hard_offline_page_store(struct device *dev,
+               return -EINVAL;
+       pfn >>= PAGE_SHIFT;
+       ret = memory_failure(pfn, 0);
++      if (ret == -EOPNOTSUPP)
++              ret = 0;
+       return ret ? ret : count;
+ }
+diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
+index aff4d27ec235..a1d6fc3c78b9 100644
+--- a/mm/hwpoison-inject.c
++++ b/mm/hwpoison-inject.c
+@@ -48,7 +48,8 @@ static int hwpoison_inject(void *data, u64 val)
+ inject:
+       pr_info("Injecting memory failure at pfn %#lx\n", pfn);
+-      return memory_failure(pfn, 0);
++      err = memory_failure(pfn, 0);
++      return (err == -EOPNOTSUPP) ? 0 : err;
+ }
+ static int hwpoison_unpoison(void *data, u64 val)
+diff --git a/mm/madvise.c b/mm/madvise.c
+index 8e5ca01a6cc0..882767d58c27 100644
+--- a/mm/madvise.c
++++ b/mm/madvise.c
+@@ -968,6 +968,8 @@ static int madvise_inject_error(int behavior,
+                       pr_info("Injecting memory failure for pfn %#lx at process virtual address %#lx\n",
+                                pfn, start);
+                       ret = memory_failure(pfn, MF_COUNT_INCREASED);
++                      if (ret == -EOPNOTSUPP)
++                              ret = 0;
+               }
+               if (ret)
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index e6425d959fa9..5664bafd5e77 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1444,7 +1444,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
+                               if (TestClearPageHWPoison(head))
+                                       num_poisoned_pages_dec();
+                               unlock_page(head);
+-                              return 0;
++                              return -EOPNOTSUPP;
+                       }
+                       unlock_page(head);
+                       res = MF_FAILED;
+@@ -1525,7 +1525,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
+               goto out;
+       if (hwpoison_filter(page)) {
+-              rc = 0;
++              rc = -EOPNOTSUPP;
+               goto unlock;
+       }
+@@ -1594,6 +1594,10 @@ static DEFINE_MUTEX(mf_mutex);
+  *
+  * Must run in process context (e.g. a work queue) with interrupts
+  * enabled and no spinlocks hold.
++ *
++ * Return: 0 for successfully handled the memory error,
++ *         -EOPNOTSUPP for memory_filter() filtered the error event,
++ *         < 0(except -EOPNOTSUPP) on failure.
+  */
+ int memory_failure(unsigned long pfn, int flags)
+ {
+@@ -1742,6 +1746,7 @@ int memory_failure(unsigned long pfn, int flags)
+                       num_poisoned_pages_dec();
+               unlock_page(p);
+               put_page(p);
++              res = -EOPNOTSUPP;
+               goto unlock_mutex;
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.15/mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch b/queue-5.15/mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch
new file mode 100644 (file)
index 0000000..ddbdcfa
--- /dev/null
@@ -0,0 +1,305 @@
+From c8a970ddb852ccec59093b75dea9358c01fe4900 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 Apr 2022 16:35:33 -0700
+Subject: mm/hwpoison: fix race between hugetlb free/demotion and
+ memory_failure_hugetlb()
+
+From: Naoya Horiguchi <naoya.horiguchi@nec.com>
+
+[ Upstream commit 405ce051236cc65b30bbfe490b28ce60ae6aed85 ]
+
+There is a race condition between memory_failure_hugetlb() and hugetlb
+free/demotion, which causes setting PageHWPoison flag on the wrong page.
+The one simple result is that wrong processes can be killed, but another
+(more serious) one is that the actual error is left unhandled, so no one
+prevents later access to it, and that might lead to more serious results
+like consuming corrupted data.
+
+Think about the below race window:
+
+  CPU 1                                   CPU 2
+  memory_failure_hugetlb
+  struct page *head = compound_head(p);
+                                          hugetlb page might be freed to
+                                          buddy, or even changed to another
+                                          compound page.
+
+  get_hwpoison_page -- page is not what we want now...
+
+The current code first does prechecks roughly and then reconfirms after
+taking refcount, but it's found that it makes code overly complicated,
+so move the prechecks in a single hugetlb_lock range.
+
+A newly introduced function, try_memory_failure_hugetlb(), always takes
+hugetlb_lock (even for non-hugetlb pages).  That can be improved, but
+memory_failure() is rare in principle, so should not be a big problem.
+
+Link: https://lkml.kernel.org/r/20220408135323.1559401-2-naoya.horiguchi@linux.dev
+Fixes: 761ad8d7c7b5 ("mm: hwpoison: introduce memory_failure_hugetlb()")
+Signed-off-by: Naoya Horiguchi <naoya.horiguchi@nec.com>
+Reported-by: Mike Kravetz <mike.kravetz@oracle.com>
+Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
+Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
+Cc: Yang Shi <shy828301@gmail.com>
+Cc: Dan Carpenter <dan.carpenter@oracle.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/hugetlb.h |   6 ++
+ include/linux/mm.h      |   8 +++
+ mm/hugetlb.c            |  10 +++
+ mm/memory-failure.c     | 137 ++++++++++++++++++++++++++++++----------
+ 4 files changed, 127 insertions(+), 34 deletions(-)
+
+diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
+index 1faebe1cd0ed..22c1d935e22d 100644
+--- a/include/linux/hugetlb.h
++++ b/include/linux/hugetlb.h
+@@ -167,6 +167,7 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
+                                               long freed);
+ bool isolate_huge_page(struct page *page, struct list_head *list);
+ int get_hwpoison_huge_page(struct page *page, bool *hugetlb);
++int get_huge_page_for_hwpoison(unsigned long pfn, int flags);
+ void putback_active_hugepage(struct page *page);
+ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
+ void free_huge_page(struct page *page);
+@@ -362,6 +363,11 @@ static inline int get_hwpoison_huge_page(struct page *page, bool *hugetlb)
+       return 0;
+ }
++static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++      return 0;
++}
++
+ static inline void putback_active_hugepage(struct page *page)
+ {
+ }
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index 7a80a08eec84..c5fa46e9c0ca 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -3132,6 +3132,14 @@ extern int sysctl_memory_failure_recovery;
+ extern void shake_page(struct page *p);
+ extern atomic_long_t num_poisoned_pages __read_mostly;
+ extern int soft_offline_page(unsigned long pfn, int flags);
++#ifdef CONFIG_MEMORY_FAILURE
++extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags);
++#else
++static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++      return 0;
++}
++#endif
+ /*
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index e4c717b08cfe..eed96302897a 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -6290,6 +6290,16 @@ int get_hwpoison_huge_page(struct page *page, bool *hugetlb)
+       return ret;
+ }
++int get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++      int ret;
++
++      spin_lock_irq(&hugetlb_lock);
++      ret = __get_huge_page_for_hwpoison(pfn, flags);
++      spin_unlock_irq(&hugetlb_lock);
++      return ret;
++}
++
+ void putback_active_hugepage(struct page *page)
+ {
+       spin_lock_irq(&hugetlb_lock);
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index a4d70c21c146..ecd64b203272 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1419,50 +1419,113 @@ static int try_to_split_thp_page(struct page *page, const char *msg)
+       return 0;
+ }
+-static int memory_failure_hugetlb(unsigned long pfn, int flags)
++/*
++ * Called from hugetlb code with hugetlb_lock held.
++ *
++ * Return values:
++ *   0             - free hugepage
++ *   1             - in-use hugepage
++ *   2             - not a hugepage
++ *   -EBUSY        - the hugepage is busy (try to retry)
++ *   -EHWPOISON    - the hugepage is already hwpoisoned
++ */
++int __get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++      struct page *page = pfn_to_page(pfn);
++      struct page *head = compound_head(page);
++      int ret = 2;    /* fallback to normal page handling */
++      bool count_increased = false;
++
++      if (!PageHeadHuge(head))
++              goto out;
++
++      if (flags & MF_COUNT_INCREASED) {
++              ret = 1;
++              count_increased = true;
++      } else if (HPageFreed(head) || HPageMigratable(head)) {
++              ret = get_page_unless_zero(head);
++              if (ret)
++                      count_increased = true;
++      } else {
++              ret = -EBUSY;
++              goto out;
++      }
++
++      if (TestSetPageHWPoison(head)) {
++              ret = -EHWPOISON;
++              goto out;
++      }
++
++      return ret;
++out:
++      if (count_increased)
++              put_page(head);
++      return ret;
++}
++
++#ifdef CONFIG_HUGETLB_PAGE
++/*
++ * Taking refcount of hugetlb pages needs extra care about race conditions
++ * with basic operations like hugepage allocation/free/demotion.
++ * So some of prechecks for hwpoison (pinning, and testing/setting
++ * PageHWPoison) should be done in single hugetlb_lock range.
++ */
++static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb)
+ {
+-      struct page *p = pfn_to_page(pfn);
+-      struct page *head = compound_head(p);
+       int res;
++      struct page *p = pfn_to_page(pfn);
++      struct page *head;
+       unsigned long page_flags;
++      bool retry = true;
+-      if (TestSetPageHWPoison(head)) {
+-              pr_err("Memory failure: %#lx: already hardware poisoned\n",
+-                     pfn);
+-              res = -EHWPOISON;
+-              if (flags & MF_ACTION_REQUIRED)
++      *hugetlb = 1;
++retry:
++      res = get_huge_page_for_hwpoison(pfn, flags);
++      if (res == 2) { /* fallback to normal page handling */
++              *hugetlb = 0;
++              return 0;
++      } else if (res == -EHWPOISON) {
++              pr_err("Memory failure: %#lx: already hardware poisoned\n", pfn);
++              if (flags & MF_ACTION_REQUIRED) {
++                      head = compound_head(p);
+                       res = kill_accessing_process(current, page_to_pfn(head), flags);
++              }
++              return res;
++      } else if (res == -EBUSY) {
++              if (retry) {
++                      retry = false;
++                      goto retry;
++              }
++              action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED);
+               return res;
+       }
++      head = compound_head(p);
++      lock_page(head);
++
++      if (hwpoison_filter(p)) {
++              ClearPageHWPoison(head);
++              res = -EOPNOTSUPP;
++              goto out;
++      }
++
+       num_poisoned_pages_inc();
+-      if (!(flags & MF_COUNT_INCREASED)) {
+-              res = get_hwpoison_page(p, flags);
+-              if (!res) {
+-                      lock_page(head);
+-                      if (hwpoison_filter(p)) {
+-                              if (TestClearPageHWPoison(head))
+-                                      num_poisoned_pages_dec();
+-                              unlock_page(head);
+-                              return -EOPNOTSUPP;
+-                      }
+-                      unlock_page(head);
+-                      res = MF_FAILED;
+-                      if (__page_handle_poison(p)) {
+-                              page_ref_inc(p);
+-                              res = MF_RECOVERED;
+-                      }
+-                      action_result(pfn, MF_MSG_FREE_HUGE, res);
+-                      return res == MF_RECOVERED ? 0 : -EBUSY;
+-              } else if (res < 0) {
+-                      action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED);
+-                      return -EBUSY;
++      /*
++       * Handling free hugepage.  The possible race with hugepage allocation
++       * or demotion can be prevented by PageHWPoison flag.
++       */
++      if (res == 0) {
++              unlock_page(head);
++              res = MF_FAILED;
++              if (__page_handle_poison(p)) {
++                      page_ref_inc(p);
++                      res = MF_RECOVERED;
+               }
++              action_result(pfn, MF_MSG_FREE_HUGE, res);
++              return res == MF_RECOVERED ? 0 : -EBUSY;
+       }
+-      lock_page(head);
+-
+       /*
+        * The page could have changed compound pages due to race window.
+        * If this happens just bail out.
+@@ -1501,6 +1564,12 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
+       unlock_page(head);
+       return res;
+ }
++#else
++static inline int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb)
++{
++      return 0;
++}
++#endif
+ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
+               struct dev_pagemap *pgmap)
+@@ -1620,6 +1689,7 @@ int memory_failure(unsigned long pfn, int flags)
+       int res = 0;
+       unsigned long page_flags;
+       bool retry = true;
++      int hugetlb = 0;
+       if (!sysctl_memory_failure_recovery)
+               panic("Memory failure on page %lx", pfn);
+@@ -1640,10 +1710,9 @@ int memory_failure(unsigned long pfn, int flags)
+       mutex_lock(&mf_mutex);
+ try_again:
+-      if (PageHuge(p)) {
+-              res = memory_failure_hugetlb(pfn, flags);
++      res = try_memory_failure_hugetlb(pfn, flags, &hugetlb);
++      if (hugetlb)
+               goto unlock_mutex;
+-      }
+       if (TestSetPageHWPoison(p)) {
+               pr_err("Memory failure: %#lx: already hardware poisoned\n",
+-- 
+2.35.1
+
diff --git a/queue-5.15/mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch b/queue-5.15/mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch
new file mode 100644 (file)
index 0000000..d2d29db
--- /dev/null
@@ -0,0 +1,222 @@
+From 37d6e57e30a76da61bd50ea469d272175c5ea977 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Jan 2022 14:09:02 -0800
+Subject: mm/hwpoison: mf_mutex for soft offline and unpoison
+
+From: Naoya Horiguchi <naoya.horiguchi@nec.com>
+
+[ Upstream commit 91d005479e06392617bacc114509d611b705eaac ]
+
+Patch series "mm/hwpoison: fix unpoison_memory()", v4.
+
+The main purpose of this series is to sync unpoison code to recent
+changes around how hwpoison code takes page refcount.  Unpoison should
+work or simply fail (without crash) if impossible.
+
+The recent works of keeping hwpoison pages in shmem pagecache introduce
+a new state of hwpoisoned pages, but unpoison for such pages is not
+supported yet with this series.
+
+It seems that soft-offline and unpoison can be used as general purpose
+page offline/online mechanism (not in the context of memory error).  I
+think that we need some additional works to realize it because currently
+soft-offline and unpoison are assumed not to happen so frequently (print
+out too many messages for aggressive usecases).  But anyway this could
+be another interesting next topic.
+
+v1: https://lore.kernel.org/linux-mm/20210614021212.223326-1-nao.horiguchi@gmail.com/
+v2: https://lore.kernel.org/linux-mm/20211025230503.2650970-1-naoya.horiguchi@linux.dev/
+v3: https://lore.kernel.org/linux-mm/20211105055058.3152564-1-naoya.horiguchi@linux.dev/
+
+This patch (of 3):
+
+Originally mf_mutex is introduced to serialize multiple MCE events, but
+it is not that useful to allow unpoison to run in parallel with
+memory_failure() and soft offline.  So apply mf_mutex to soft offline
+and unpoison.  The memory failure handler and soft offline handler get
+simpler with this.
+
+Link: https://lkml.kernel.org/r/20211115084006.3728254-1-naoya.horiguchi@linux.dev
+Link: https://lkml.kernel.org/r/20211115084006.3728254-2-naoya.horiguchi@linux.dev
+Signed-off-by: Naoya Horiguchi <naoya.horiguchi@nec.com>
+Reviewed-by: Yang Shi <shy828301@gmail.com>
+Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
+Cc: David Hildenbrand <david@redhat.com>
+Cc: Ding Hui <dinghui@sangfor.com.cn>
+Cc: Miaohe Lin <linmiaohe@huawei.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ mm/memory-failure.c | 62 +++++++++++++--------------------------------
+ 1 file changed, 18 insertions(+), 44 deletions(-)
+
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index c3ceb7436933..e6425d959fa9 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1463,14 +1463,6 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
+       lock_page(head);
+       page_flags = head->flags;
+-      if (!PageHWPoison(head)) {
+-              pr_err("Memory failure: %#lx: just unpoisoned\n", pfn);
+-              num_poisoned_pages_dec();
+-              unlock_page(head);
+-              put_page(head);
+-              return 0;
+-      }
+-
+       /*
+        * TODO: hwpoison for pud-sized hugetlb doesn't work right now, so
+        * simply disable it. In order to make it work properly, we need
+@@ -1584,6 +1576,8 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
+       return rc;
+ }
++static DEFINE_MUTEX(mf_mutex);
++
+ /**
+  * memory_failure - Handle memory failure of a page.
+  * @pfn: Page Number of the corrupted page
+@@ -1610,7 +1604,6 @@ int memory_failure(unsigned long pfn, int flags)
+       int res = 0;
+       unsigned long page_flags;
+       bool retry = true;
+-      static DEFINE_MUTEX(mf_mutex);
+       if (!sysctl_memory_failure_recovery)
+               panic("Memory failure on page %lx", pfn);
+@@ -1744,16 +1737,6 @@ int memory_failure(unsigned long pfn, int flags)
+        */
+       page_flags = p->flags;
+-      /*
+-       * unpoison always clear PG_hwpoison inside page lock
+-       */
+-      if (!PageHWPoison(p)) {
+-              pr_err("Memory failure: %#lx: just unpoisoned\n", pfn);
+-              num_poisoned_pages_dec();
+-              unlock_page(p);
+-              put_page(p);
+-              goto unlock_mutex;
+-      }
+       if (hwpoison_filter(p)) {
+               if (TestClearPageHWPoison(p))
+                       num_poisoned_pages_dec();
+@@ -1934,6 +1917,7 @@ int unpoison_memory(unsigned long pfn)
+       struct page *page;
+       struct page *p;
+       int freeit = 0;
++      int ret = 0;
+       unsigned long flags = 0;
+       static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
+                                       DEFAULT_RATELIMIT_BURST);
+@@ -1944,39 +1928,30 @@ int unpoison_memory(unsigned long pfn)
+       p = pfn_to_page(pfn);
+       page = compound_head(p);
++      mutex_lock(&mf_mutex);
++
+       if (!PageHWPoison(p)) {
+               unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n",
+                                pfn, &unpoison_rs);
+-              return 0;
++              goto unlock_mutex;
+       }
+       if (page_count(page) > 1) {
+               unpoison_pr_info("Unpoison: Someone grabs the hwpoison page %#lx\n",
+                                pfn, &unpoison_rs);
+-              return 0;
++              goto unlock_mutex;
+       }
+       if (page_mapped(page)) {
+               unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n",
+                                pfn, &unpoison_rs);
+-              return 0;
++              goto unlock_mutex;
+       }
+       if (page_mapping(page)) {
+               unpoison_pr_info("Unpoison: the hwpoison page has non-NULL mapping %#lx\n",
+                                pfn, &unpoison_rs);
+-              return 0;
+-      }
+-
+-      /*
+-       * unpoison_memory() can encounter thp only when the thp is being
+-       * worked by memory_failure() and the page lock is not held yet.
+-       * In such case, we yield to memory_failure() and make unpoison fail.
+-       */
+-      if (!PageHuge(page) && PageTransHuge(page)) {
+-              unpoison_pr_info("Unpoison: Memory failure is now running on %#lx\n",
+-                               pfn, &unpoison_rs);
+-              return 0;
++              goto unlock_mutex;
+       }
+       if (!get_hwpoison_page(p, flags)) {
+@@ -1984,29 +1959,23 @@ int unpoison_memory(unsigned long pfn)
+                       num_poisoned_pages_dec();
+               unpoison_pr_info("Unpoison: Software-unpoisoned free page %#lx\n",
+                                pfn, &unpoison_rs);
+-              return 0;
++              goto unlock_mutex;
+       }
+-      lock_page(page);
+-      /*
+-       * This test is racy because PG_hwpoison is set outside of page lock.
+-       * That's acceptable because that won't trigger kernel panic. Instead,
+-       * the PG_hwpoison page will be caught and isolated on the entrance to
+-       * the free buddy page pool.
+-       */
+       if (TestClearPageHWPoison(page)) {
+               unpoison_pr_info("Unpoison: Software-unpoisoned page %#lx\n",
+                                pfn, &unpoison_rs);
+               num_poisoned_pages_dec();
+               freeit = 1;
+       }
+-      unlock_page(page);
+       put_page(page);
+       if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1))
+               put_page(page);
+-      return 0;
++unlock_mutex:
++      mutex_unlock(&mf_mutex);
++      return ret;
+ }
+ EXPORT_SYMBOL(unpoison_memory);
+@@ -2187,9 +2156,12 @@ int soft_offline_page(unsigned long pfn, int flags)
+               return -EIO;
+       }
++      mutex_lock(&mf_mutex);
++
+       if (PageHWPoison(page)) {
+               pr_info("%s: %#lx page already poisoned\n", __func__, pfn);
+               put_ref_page(ref_page);
++              mutex_unlock(&mf_mutex);
+               return 0;
+       }
+@@ -2208,5 +2180,7 @@ int soft_offline_page(unsigned long pfn, int flags)
+               }
+       }
++      mutex_unlock(&mf_mutex);
++
+       return ret;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/mm-memory-failure.c-fix-race-with-changing-page-comp.patch b/queue-5.15/mm-memory-failure.c-fix-race-with-changing-page-comp.patch
new file mode 100644 (file)
index 0000000..a9656c2
--- /dev/null
@@ -0,0 +1,107 @@
+From b4e44dfaac719d6981fdb1c6a0089279e142bc41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 22 Mar 2022 14:44:44 -0700
+Subject: mm/memory-failure.c: fix race with changing page compound again
+
+From: Miaohe Lin <linmiaohe@huawei.com>
+
+[ Upstream commit 888af2701db79b9b27c7e37f9ede528a5ca53b76 ]
+
+Patch series "A few fixup patches for memory failure", v2.
+
+This series contains a few patches to fix the race with changing page
+compound page, make non-LRU movable pages unhandlable and so on.  More
+details can be found in the respective changelogs.
+
+There is a race window where we got the compound_head, the hugetlb page
+could be freed to buddy, or even changed to another compound page just
+before we try to get hwpoison page.  Think about the below race window:
+
+  CPU 1                                          CPU 2
+  memory_failure_hugetlb
+  struct page *head = compound_head(p);
+                                         hugetlb page might be freed to
+                                         buddy, or even changed to another
+                                         compound page.
+
+  get_hwpoison_page -- page is not what we want now...
+
+If this race happens, just bail out.  Also MF_MSG_DIFFERENT_PAGE_SIZE is
+introduced to record this event.
+
+[akpm@linux-foundation.org: s@/**@/*@, per Naoya Horiguchi]
+
+Link: https://lkml.kernel.org/r/20220312074613.4798-1-linmiaohe@huawei.com
+Link: https://lkml.kernel.org/r/20220312074613.4798-2-linmiaohe@huawei.com
+Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
+Acked-by: Naoya Horiguchi <naoya.horiguchi@nec.com>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Mike Kravetz <mike.kravetz@oracle.com>
+Cc: Yang Shi <shy828301@gmail.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/mm.h      |  1 +
+ include/ras/ras_event.h |  1 +
+ mm/memory-failure.c     | 12 ++++++++++++
+ 3 files changed, 14 insertions(+)
+
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index 85205adcdd0d..7a80a08eec84 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -3167,6 +3167,7 @@ enum mf_action_page_type {
+       MF_MSG_BUDDY_2ND,
+       MF_MSG_DAX,
+       MF_MSG_UNSPLIT_THP,
++      MF_MSG_DIFFERENT_PAGE_SIZE,
+       MF_MSG_UNKNOWN,
+ };
+diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
+index 0bdbc0d17d2f..cac13ff1d6eb 100644
+--- a/include/ras/ras_event.h
++++ b/include/ras/ras_event.h
+@@ -376,6 +376,7 @@ TRACE_EVENT(aer_event,
+       EM ( MF_MSG_BUDDY_2ND, "free buddy page (2nd try)" )            \
+       EM ( MF_MSG_DAX, "dax page" )                                   \
+       EM ( MF_MSG_UNSPLIT_THP, "unsplit thp" )                        \
++      EM ( MF_MSG_DIFFERENT_PAGE_SIZE, "different page size" )        \
+       EMe ( MF_MSG_UNKNOWN, "unknown page" )
+ /*
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index 5664bafd5e77..a4d70c21c146 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -741,6 +741,7 @@ static const char * const action_page_types[] = {
+       [MF_MSG_BUDDY_2ND]              = "free buddy page (2nd try)",
+       [MF_MSG_DAX]                    = "dax page",
+       [MF_MSG_UNSPLIT_THP]            = "unsplit thp",
++      [MF_MSG_DIFFERENT_PAGE_SIZE]    = "different page size",
+       [MF_MSG_UNKNOWN]                = "unknown page",
+ };
+@@ -1461,6 +1462,17 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
+       }
+       lock_page(head);
++
++      /*
++       * The page could have changed compound pages due to race window.
++       * If this happens just bail out.
++       */
++      if (!PageHuge(p) || compound_head(p) != head) {
++              action_result(pfn, MF_MSG_DIFFERENT_PAGE_SIZE, MF_IGNORED);
++              res = -EBUSY;
++              goto out;
++      }
++
+       page_flags = head->flags;
+       /*
+-- 
+2.35.1
+
diff --git a/queue-5.15/mm-vmalloc-introduce-array-allocation-functions.patch b/queue-5.15/mm-vmalloc-introduce-array-allocation-functions.patch
new file mode 100644 (file)
index 0000000..9b56840
--- /dev/null
@@ -0,0 +1,102 @@
+From 0fe8b2ff024aec861bac0aa495b13c94e728883c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Mar 2022 04:47:22 -0500
+Subject: mm: vmalloc: introduce array allocation functions
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+[ Upstream commit a8749a35c39903120ec421ef2525acc8e0daa55c ]
+
+Linux has dozens of occurrences of vmalloc(array_size()) and
+vzalloc(array_size()).  Allow to simplify the code by providing
+vmalloc_array and vcalloc, as well as the underscored variants that let
+the caller specify the GFP flags.
+
+Acked-by: Michal Hocko <mhocko@suse.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/vmalloc.h |  5 +++++
+ mm/util.c               | 50 +++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 55 insertions(+)
+
+diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
+index 4fe9e885bbfa..5535be1012a2 100644
+--- a/include/linux/vmalloc.h
++++ b/include/linux/vmalloc.h
+@@ -159,6 +159,11 @@ void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask,
+               int node, const void *caller);
+ void *vmalloc_no_huge(unsigned long size);
++extern void *__vmalloc_array(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2);
++extern void *vmalloc_array(size_t n, size_t size) __alloc_size(1, 2);
++extern void *__vcalloc(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2);
++extern void *vcalloc(size_t n, size_t size) __alloc_size(1, 2);
++
+ extern void vfree(const void *addr);
+ extern void vfree_atomic(const void *addr);
+diff --git a/mm/util.c b/mm/util.c
+index 3073de05c2bd..ea04979f131e 100644
+--- a/mm/util.c
++++ b/mm/util.c
+@@ -698,6 +698,56 @@ static inline void *__page_rmapping(struct page *page)
+       return (void *)mapping;
+ }
++/**
++ * __vmalloc_array - allocate memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ * @flags: the type of memory to allocate (see kmalloc).
++ */
++void *__vmalloc_array(size_t n, size_t size, gfp_t flags)
++{
++      size_t bytes;
++
++      if (unlikely(check_mul_overflow(n, size, &bytes)))
++              return NULL;
++      return __vmalloc(bytes, flags);
++}
++EXPORT_SYMBOL(__vmalloc_array);
++
++/**
++ * vmalloc_array - allocate memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ */
++void *vmalloc_array(size_t n, size_t size)
++{
++      return __vmalloc_array(n, size, GFP_KERNEL);
++}
++EXPORT_SYMBOL(vmalloc_array);
++
++/**
++ * __vcalloc - allocate and zero memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ * @flags: the type of memory to allocate (see kmalloc).
++ */
++void *__vcalloc(size_t n, size_t size, gfp_t flags)
++{
++      return __vmalloc_array(n, size, flags | __GFP_ZERO);
++}
++EXPORT_SYMBOL(__vcalloc);
++
++/**
++ * vcalloc - allocate and zero memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ */
++void *vcalloc(size_t n, size_t size)
++{
++      return __vmalloc_array(n, size, GFP_KERNEL | __GFP_ZERO);
++}
++EXPORT_SYMBOL(vcalloc);
++
+ /* Neutral page->mapping pointer to address_space or anon_vma or other */
+ void *page_rmapping(struct page *page)
+ {
+-- 
+2.35.1
+
diff --git a/queue-5.15/module-change-to-print-useful-messages-from-elf_vali.patch b/queue-5.15/module-change-to-print-useful-messages-from-elf_vali.patch
new file mode 100644 (file)
index 0000000..f934638
--- /dev/null
@@ -0,0 +1,179 @@
+From fc77dede4f15185c8c414633566597c2e5399f2d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Oct 2021 14:57:40 -0600
+Subject: module: change to print useful messages from elf_validity_check()
+
+From: Shuah Khan <skhan@linuxfoundation.org>
+
+[ Upstream commit 7fd982f394c42f25a73fe9dfbf1e6b11fa26b40a ]
+
+elf_validity_check() checks ELF headers for errors and ELF Spec.
+compliance and if any of them fail it returns -ENOEXEC from all of
+these error paths. Almost all of them don't print any messages.
+
+When elf_validity_check() returns an error, load_module() prints an
+error message without error code. It is hard to determine why the
+module ELF structure is invalid, even if load_module() prints the
+error code which is -ENOEXEC in all of these cases.
+
+Change to print useful error messages from elf_validity_check() to
+clearly say what went wrong and why the ELF validity checks failed.
+
+Remove the load_module() error message which is no longer needed.
+This patch includes changes to fix build warns on 32-bit platforms:
+
+warning: format '%llu' expects argument of type 'long long unsigned int',
+but argument 3 has type 'Elf32_Off' {aka 'unsigned int'}
+Reported-by: kernel test robot <lkp@intel.com>
+
+Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
+Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/module.c | 75 +++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 54 insertions(+), 21 deletions(-)
+
+diff --git a/kernel/module.c b/kernel/module.c
+index 83991c2d5af9..256b3c80a771 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2967,14 +2967,29 @@ static int elf_validity_check(struct load_info *info)
+       Elf_Shdr *shdr, *strhdr;
+       int err;
+-      if (info->len < sizeof(*(info->hdr)))
+-              return -ENOEXEC;
++      if (info->len < sizeof(*(info->hdr))) {
++              pr_err("Invalid ELF header len %lu\n", info->len);
++              goto no_exec;
++      }
+-      if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
+-          || info->hdr->e_type != ET_REL
+-          || !elf_check_arch(info->hdr)
+-          || info->hdr->e_shentsize != sizeof(Elf_Shdr))
+-              return -ENOEXEC;
++      if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0) {
++              pr_err("Invalid ELF header magic: != %s\n", ELFMAG);
++              goto no_exec;
++      }
++      if (info->hdr->e_type != ET_REL) {
++              pr_err("Invalid ELF header type: %u != %u\n",
++                     info->hdr->e_type, ET_REL);
++              goto no_exec;
++      }
++      if (!elf_check_arch(info->hdr)) {
++              pr_err("Invalid architecture in ELF header: %u\n",
++                     info->hdr->e_machine);
++              goto no_exec;
++      }
++      if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) {
++              pr_err("Invalid ELF section header size\n");
++              goto no_exec;
++      }
+       /*
+        * e_shnum is 16 bits, and sizeof(Elf_Shdr) is
+@@ -2983,8 +2998,10 @@ static int elf_validity_check(struct load_info *info)
+        */
+       if (info->hdr->e_shoff >= info->len
+           || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
+-              info->len - info->hdr->e_shoff))
+-              return -ENOEXEC;
++              info->len - info->hdr->e_shoff)) {
++              pr_err("Invalid ELF section header overflow\n");
++              goto no_exec;
++      }
+       info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
+@@ -2992,13 +3009,19 @@ static int elf_validity_check(struct load_info *info)
+        * Verify if the section name table index is valid.
+        */
+       if (info->hdr->e_shstrndx == SHN_UNDEF
+-          || info->hdr->e_shstrndx >= info->hdr->e_shnum)
+-              return -ENOEXEC;
++          || info->hdr->e_shstrndx >= info->hdr->e_shnum) {
++              pr_err("Invalid ELF section name index: %d || e_shstrndx (%d) >= e_shnum (%d)\n",
++                     info->hdr->e_shstrndx, info->hdr->e_shstrndx,
++                     info->hdr->e_shnum);
++              goto no_exec;
++      }
+       strhdr = &info->sechdrs[info->hdr->e_shstrndx];
+       err = validate_section_offset(info, strhdr);
+-      if (err < 0)
++      if (err < 0) {
++              pr_err("Invalid ELF section hdr(type %u)\n", strhdr->sh_type);
+               return err;
++      }
+       /*
+        * The section name table must be NUL-terminated, as required
+@@ -3006,8 +3029,10 @@ static int elf_validity_check(struct load_info *info)
+        * strings in the section safe.
+        */
+       info->secstrings = (void *)info->hdr + strhdr->sh_offset;
+-      if (info->secstrings[strhdr->sh_size - 1] != '\0')
+-              return -ENOEXEC;
++      if (info->secstrings[strhdr->sh_size - 1] != '\0') {
++              pr_err("ELF Spec violation: section name table isn't null terminated\n");
++              goto no_exec;
++      }
+       /*
+        * The code assumes that section 0 has a length of zero and
+@@ -3015,8 +3040,11 @@ static int elf_validity_check(struct load_info *info)
+        */
+       if (info->sechdrs[0].sh_type != SHT_NULL
+           || info->sechdrs[0].sh_size != 0
+-          || info->sechdrs[0].sh_addr != 0)
+-              return -ENOEXEC;
++          || info->sechdrs[0].sh_addr != 0) {
++              pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n",
++                     info->sechdrs[0].sh_type);
++              goto no_exec;
++      }
+       for (i = 1; i < info->hdr->e_shnum; i++) {
+               shdr = &info->sechdrs[i];
+@@ -3026,8 +3054,12 @@ static int elf_validity_check(struct load_info *info)
+                       continue;
+               case SHT_SYMTAB:
+                       if (shdr->sh_link == SHN_UNDEF
+-                          || shdr->sh_link >= info->hdr->e_shnum)
+-                              return -ENOEXEC;
++                          || shdr->sh_link >= info->hdr->e_shnum) {
++                              pr_err("Invalid ELF sh_link!=SHN_UNDEF(%d) or (sh_link(%d) >= hdr->e_shnum(%d)\n",
++                                     shdr->sh_link, shdr->sh_link,
++                                     info->hdr->e_shnum);
++                              goto no_exec;
++                      }
+                       fallthrough;
+               default:
+                       err = validate_section_offset(info, shdr);
+@@ -3049,6 +3081,9 @@ static int elf_validity_check(struct load_info *info)
+       }
+       return 0;
++
++no_exec:
++      return -ENOEXEC;
+ }
+ #define COPY_CHUNK_SIZE (16*PAGE_SIZE)
+@@ -3925,10 +3960,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
+        * sections.
+        */
+       err = elf_validity_check(info);
+-      if (err) {
+-              pr_err("Module has invalid ELF structures\n");
++      if (err)
+               goto free_copy;
+-      }
+       /*
+        * Everything checks out, so set up the section info
+-- 
+2.35.1
+
diff --git a/queue-5.15/module-fix-e_shstrndx-.sh_size-0-oob-access.patch b/queue-5.15/module-fix-e_shstrndx-.sh_size-0-oob-access.patch
new file mode 100644 (file)
index 0000000..7231209
--- /dev/null
@@ -0,0 +1,47 @@
+From 1fc8cfecf39c2e0b0a67d72401f23424ee1f20ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 May 2022 12:54:20 +0300
+Subject: module: fix [e_shstrndx].sh_size=0 OOB access
+
+From: Alexey Dobriyan <adobriyan@gmail.com>
+
+[ Upstream commit 391e982bfa632b8315235d8be9c0a81374c6a19c ]
+
+It is trivial to craft a module to trigger OOB access in this line:
+
+       if (info->secstrings[strhdr->sh_size - 1] != '\0') {
+
+BUG: unable to handle page fault for address: ffffc90000aa0fff
+PGD 100000067 P4D 100000067 PUD 100066067 PMD 10436f067 PTE 0
+Oops: 0000 [#1] PREEMPT SMP PTI
+CPU: 7 PID: 1215 Comm: insmod Not tainted 5.18.0-rc5-00007-g9bf578647087-dirty #10
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-4.fc34 04/01/2014
+RIP: 0010:load_module+0x19b/0x2391
+
+Fixes: ec2a29593c83 ("module: harden ELF info handling")
+Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
+[rebased patch onto modules-next]
+Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/module.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/kernel/module.c b/kernel/module.c
+index 256b3c80a771..ef79f4dbda87 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -3029,6 +3029,10 @@ static int elf_validity_check(struct load_info *info)
+        * strings in the section safe.
+        */
+       info->secstrings = (void *)info->hdr + strhdr->sh_offset;
++      if (strhdr->sh_size == 0) {
++              pr_err("empty section name table\n");
++              goto no_exec;
++      }
+       if (info->secstrings[strhdr->sh_size - 1] != '\0') {
+               pr_err("ELF Spec violation: section name table isn't null terminated\n");
+               goto no_exec;
+-- 
+2.35.1
+
diff --git a/queue-5.15/mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch b/queue-5.15/mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch
new file mode 100644 (file)
index 0000000..388390f
--- /dev/null
@@ -0,0 +1,36 @@
+From 750c534564011a8c06417ea3955a3d674dd8ea7e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Dec 2021 16:33:55 +0800
+Subject: mt76: mt76_connac: fix MCU_CE_CMD_SET_ROC definition error
+
+From: Sean Wang <sean.wang@mediatek.com>
+
+[ Upstream commit bf9727a27442a50c75b7d99a5088330c578b2a42 ]
+
+Fixed an MCU_CE_CMD_SET_ROC definition error that occurred from a previous
+refactor work.
+
+Fixes: d0e274af2f2e4 ("mt76: mt76_connac: create mcu library")
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+index 77d4435e4581..72a70a7046fb 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+@@ -556,7 +556,7 @@ enum {
+       MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16,
+       MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17,
+       MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b,
+-      MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1d,
++      MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1c,
+       MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33,
+       MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d,
+       MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61,
+-- 
+2.35.1
+
diff --git a/queue-5.15/mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch b/queue-5.15/mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch
new file mode 100644 (file)
index 0000000..3a05388
--- /dev/null
@@ -0,0 +1,46 @@
+From 75e5d37892bfbf6dc35d880cf42d809dbd361a67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Dec 2021 12:36:02 +0100
+Subject: mt76: mt7921: do not always disable fw runtime-pm
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit b44eeb8cbdf2b88f2844f11e4f263b0abed5b5b0 ]
+
+After commit 'd430dffbe9dd ("mt76: mt7921: fix a possible race
+enabling/disabling runtime-pm")', runtime-pm is always disabled in the
+fw even if the user requests to enable it toggling debugfs node since
+mt7921_pm_interface_iter routine will use pm->enable to configure the fw.
+Fix the issue moving enable variable configuration before running
+mt7921_pm_interface_iter routine.
+
+Fixes: d430dffbe9dd ("mt76: mt7921: fix a possible race enabling/disabling runtime-pm")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+index b9f25599227d..cfcf7964c688 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+@@ -291,13 +291,12 @@ mt7921_pm_set(void *data, u64 val)
+       pm->enable = false;
+       mt76_connac_pm_wake(&dev->mphy, pm);
++      pm->enable = val;
+       ieee80211_iterate_active_interfaces(mt76_hw(dev),
+                                           IEEE80211_IFACE_ITER_RESUME_ALL,
+                                           mt7921_pm_interface_iter, dev);
+       mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
+-
+-      pm->enable = val;
+       mt76_connac_power_save_sched(&dev->mphy, pm);
+ out:
+       mutex_unlock(&dev->mt76.mutex);
+-- 
+2.35.1
+
diff --git a/queue-5.15/mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch b/queue-5.15/mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch
new file mode 100644 (file)
index 0000000..0d634c7
--- /dev/null
@@ -0,0 +1,82 @@
+From 79d1311e3ae778795f8d8ea317d45b7f48bde8e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 21 Dec 2021 14:57:09 +0100
+Subject: mt76: mt7921: fix a possible race enabling/disabling runtime-pm
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit d430dffbe9dd30759f3c64b65bf85b0245c8d8ab ]
+
+Fix a possible race enabling/disabling runtime-pm between
+mt7921_pm_set() and mt7921_poll_rx() since mt7921_pm_wake_work()
+always schedules rx-napi callback and it will trigger
+mt7921_pm_power_save_work routine putting chip to in low-power state
+during mt7921_pm_set processing.
+
+Suggested-by: Deren Wu <deren.wu@mediatek.com>
+Tested-by: Deren Wu <deren.wu@mediatek.com>
+Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support")
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/0f3e075a2033dc05f09dab4059e5be8cbdccc239.1640094847.git.lorenzo@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c |  3 ---
+ drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c  | 12 +++++++++---
+ 2 files changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+index af43bcb54578..306e9eaea917 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+@@ -7,9 +7,6 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
+ {
+       struct mt76_dev *dev = phy->dev;
+-      if (!pm->enable)
+-              return 0;
+-
+       if (mt76_is_usb(dev))
+               return 0;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+index 82fb2585f413..b9f25599227d 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+@@ -276,7 +276,7 @@ mt7921_pm_set(void *data, u64 val)
+       struct mt7921_dev *dev = data;
+       struct mt76_connac_pm *pm = &dev->pm;
+-      mt7921_mutex_acquire(dev);
++      mutex_lock(&dev->mt76.mutex);
+       if (val == pm->enable)
+               goto out;
+@@ -285,7 +285,11 @@ mt7921_pm_set(void *data, u64 val)
+               pm->stats.last_wake_event = jiffies;
+               pm->stats.last_doze_event = jiffies;
+       }
+-      pm->enable = val;
++      /* make sure the chip is awake here and ps_work is scheduled
++       * just at end of the this routine.
++       */
++      pm->enable = false;
++      mt76_connac_pm_wake(&dev->mphy, pm);
+       ieee80211_iterate_active_interfaces(mt76_hw(dev),
+                                           IEEE80211_IFACE_ITER_RESUME_ALL,
+@@ -293,8 +297,10 @@ mt7921_pm_set(void *data, u64 val)
+       mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
++      pm->enable = val;
++      mt76_connac_power_save_sched(&dev->mphy, pm);
+ out:
+-      mt7921_mutex_release(dev);
++      mutex_unlock(&dev->mt76.mutex);
+       return 0;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch b/queue-5.15/mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch
new file mode 100644 (file)
index 0000000..5630771
--- /dev/null
@@ -0,0 +1,75 @@
+From af7a84be858c67bb5ceafccb62554e831c55e569 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Aug 2021 10:38:03 +0200
+Subject: mt76: mt7921: get rid of mt7921_mac_set_beacon_filter
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit b30363102a4122f6eed37927b64a2c7ac70b8859 ]
+
+Remove mt7921_mac_set_beacon_filter routine since it is no longer used.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/mediatek/mt76/mt7921/mac.c   | 28 -------------------
+ .../wireless/mediatek/mt76/mt7921/mt7921.h    |  3 --
+ 2 files changed, 31 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+index bef8d4a76ed9..426e7a32bdc8 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+@@ -1573,34 +1573,6 @@ void mt7921_pm_power_save_work(struct work_struct *work)
+       queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
+ }
+-int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
+-                               struct ieee80211_vif *vif,
+-                               bool enable)
+-{
+-      struct mt7921_dev *dev = phy->dev;
+-      bool ext_phy = phy != &dev->phy;
+-      int err;
+-
+-      if (!dev->pm.enable)
+-              return -EOPNOTSUPP;
+-
+-      err = mt7921_mcu_set_bss_pm(dev, vif, enable);
+-      if (err)
+-              return err;
+-
+-      if (enable) {
+-              vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+-              mt76_set(dev, MT_WF_RFCR(ext_phy),
+-                       MT_WF_RFCR_DROP_OTHER_BEACON);
+-      } else {
+-              vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+-              mt76_clear(dev, MT_WF_RFCR(ext_phy),
+-                         MT_WF_RFCR_DROP_OTHER_BEACON);
+-      }
+-
+-      return 0;
+-}
+-
+ void mt7921_coredump_work(struct work_struct *work)
+ {
+       struct mt7921_dev *dev;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+index 2d8bd6bfc820..1aafd8723b3a 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+@@ -381,9 +381,6 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
+ void mt7921_pm_wake_work(struct work_struct *work);
+ void mt7921_pm_power_save_work(struct work_struct *work);
+ bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev);
+-int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
+-                               struct ieee80211_vif *vif,
+-                               bool enable);
+ void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
+ void mt7921_coredump_work(struct work_struct *work);
+ int mt7921_wfsys_reset(struct mt7921_dev *dev);
+-- 
+2.35.1
+
diff --git a/queue-5.15/mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch b/queue-5.15/mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch
new file mode 100644 (file)
index 0000000..aa2dded
--- /dev/null
@@ -0,0 +1,242 @@
+From 4d6cc28ed723bdf30fc20ec81ff0a9c65910f580 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Aug 2021 12:37:22 +0200
+Subject: mt76: mt7921: introduce mt7921_mcu_set_beacon_filter utility routine
+
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+
+[ Upstream commit 890809ca1986e63d29dd1591090af67b655ed89c ]
+
+Introduce mt7921_mcu_set_beacon_filter utility routine in order to
+remove duplicated code for hw beacon filtering.
+Move mt7921_pm_interface_iter in debugfs since it is just used there.
+Make the following routine static:
+- mt7921_pm_interface_iter
+- mt7921_mcu_uni_bss_bcnft
+- mt7921_mcu_set_bss_pm
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../wireless/mediatek/mt76/mt7921/debugfs.c   | 20 +++++---
+ .../net/wireless/mediatek/mt76/mt7921/main.c  | 33 +------------
+ .../net/wireless/mediatek/mt76/mt7921/mcu.c   | 47 ++++++++++---------
+ .../wireless/mediatek/mt76/mt7921/mt7921.h    |  8 ++--
+ 4 files changed, 45 insertions(+), 63 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+index 8d5e261cd10f..82fb2585f413 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+@@ -262,30 +262,38 @@ mt7921_txpwr(struct seq_file *s, void *data)
+       return 0;
+ }
++static void
++mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
++{
++      struct mt7921_dev *dev = priv;
++
++      mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable);
++}
++
+ static int
+ mt7921_pm_set(void *data, u64 val)
+ {
+       struct mt7921_dev *dev = data;
+       struct mt76_connac_pm *pm = &dev->pm;
+-      struct mt76_phy *mphy = dev->phy.mt76;
+-
+-      if (val == pm->enable)
+-              return 0;
+       mt7921_mutex_acquire(dev);
++      if (val == pm->enable)
++              goto out;
++
+       if (!pm->enable) {
+               pm->stats.last_wake_event = jiffies;
+               pm->stats.last_doze_event = jiffies;
+       }
+       pm->enable = val;
+-      ieee80211_iterate_active_interfaces(mphy->hw,
++      ieee80211_iterate_active_interfaces(mt76_hw(dev),
+                                           IEEE80211_IFACE_ITER_RESUME_ALL,
+-                                          mt7921_pm_interface_iter, mphy->priv);
++                                          mt7921_pm_interface_iter, dev);
+       mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
++out:
+       mt7921_mutex_release(dev);
+       return 0;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+index 30252f408ddc..13a7ae3d8351 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+@@ -528,36 +528,6 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
+       mt7921_mutex_release(dev);
+ }
+-static int
+-mt7921_bss_bcnft_apply(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+-                     bool assoc)
+-{
+-      int ret;
+-
+-      if (!dev->pm.enable)
+-              return 0;
+-
+-      if (assoc) {
+-              ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
+-              if (ret)
+-                      return ret;
+-
+-              vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+-              mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
+-
+-              return 0;
+-      }
+-
+-      ret = mt7921_mcu_set_bss_pm(dev, vif, false);
+-      if (ret)
+-              return ret;
+-
+-      vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+-      mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
+-
+-      return 0;
+-}
+-
+ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *info,
+@@ -587,7 +557,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
+       if (changed & BSS_CHANGED_ASSOC) {
+               mt7921_mcu_sta_update(dev, NULL, vif, true,
+                                     MT76_STA_INFO_STATE_ASSOC);
+-              mt7921_bss_bcnft_apply(dev, vif, info->assoc);
++              if (dev->pm.enable)
++                      mt7921_mcu_set_beacon_filter(dev, vif, info->assoc);
+       }
+       if (changed & BSS_CHANGED_ARP_FILTER) {
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+index 4119f8efd896..dabc0de2ec65 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+@@ -1205,8 +1205,9 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
+                                &ps_req, sizeof(ps_req), true);
+ }
+-int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+-                           bool enable)
++static int
++mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
++                       bool enable)
+ {
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct {
+@@ -1240,8 +1241,9 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+                                &bcnft_req, sizeof(bcnft_req), true);
+ }
+-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+-                        bool enable)
++static int
++mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
++                    bool enable)
+ {
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct {
+@@ -1390,31 +1392,34 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
+       return err;
+ }
+-void
+-mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
++int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
++                               struct ieee80211_vif *vif,
++                               bool enable)
+ {
+-      struct mt7921_phy *phy = priv;
+-      struct mt7921_dev *dev = phy->dev;
+       struct ieee80211_hw *hw = mt76_hw(dev);
+-      int ret;
+-
+-      if (dev->pm.enable)
+-              ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
+-      else
+-              ret = mt7921_mcu_set_bss_pm(dev, vif, false);
++      int err;
+-      if (ret)
+-              return;
++      if (enable) {
++              err = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
++              if (err)
++                      return err;
+-      if (dev->pm.enable) {
+               vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+               ieee80211_hw_set(hw, CONNECTION_MONITOR);
+               mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
+-      } else {
+-              vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+-              __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
+-              mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
++
++              return 0;
+       }
++
++      err = mt7921_mcu_set_bss_pm(dev, vif, false);
++      if (err)
++              return err;
++
++      vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
++      __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
++      mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
++
++      return 0;
+ }
+ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+index 1aafd8723b3a..32d4f2cab94e 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+@@ -363,6 +363,9 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy);
+ void mt7921_update_channel(struct mt76_phy *mphy);
+ int mt7921_init_debugfs(struct mt7921_dev *dev);
++int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
++                               struct ieee80211_vif *vif,
++                               bool enable);
+ int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
+                        struct ieee80211_ampdu_params *params,
+                        bool enable);
+@@ -371,17 +374,12 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
+                        bool enable);
+ void mt7921_scan_work(struct work_struct *work);
+ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
+-int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+-                           bool enable);
+-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+-                        bool enable);
+ int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
+ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
+ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
+ void mt7921_pm_wake_work(struct work_struct *work);
+ void mt7921_pm_power_save_work(struct work_struct *work);
+ bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev);
+-void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
+ void mt7921_coredump_work(struct work_struct *work);
+ int mt7921_wfsys_reset(struct mt7921_dev *dev);
+ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr);
+-- 
+2.35.1
+
diff --git a/queue-5.15/mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch b/queue-5.15/mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch
new file mode 100644 (file)
index 0000000..3679655
--- /dev/null
@@ -0,0 +1,49 @@
+From 19e11ecc859faa363850ae8ac44ffb24d0886ffe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Feb 2022 18:33:34 +0200
+Subject: mtd: spi-nor: Skip erase logic when SPI_NOR_NO_ERASE is set
+
+From: Tudor Ambarus <tudor.ambarus@microchip.com>
+
+[ Upstream commit 151c6b49d679872d6fc0b50e0ad96303091694a2 ]
+
+Even if SPI_NOR_NO_ERASE was set, one could still send erase opcodes
+to the flash. It is not recommended to send unsupported opcodes to
+flashes. Fix the logic and do not set mtd->_erase when SPI_NOR_NO_ERASE
+is specified. With this users will not be able to issue erase opcodes to
+flashes and instead they will recive an -ENOTSUPP error.
+
+Fixes: b199489d37b2 ("mtd: spi-nor: add the framework for SPI NOR")
+Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
+Reviewed-by: Michael Walle <michael@walle.cc>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20220228163334.277730-1-tudor.ambarus@microchip.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mtd/spi-nor/core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
+index 90f39aabc1ff..d97cdbc2b9de 100644
+--- a/drivers/mtd/spi-nor/core.c
++++ b/drivers/mtd/spi-nor/core.c
+@@ -3148,7 +3148,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
+       mtd->writesize = nor->params->writesize;
+       mtd->flags = MTD_CAP_NORFLASH;
+       mtd->size = nor->params->size;
+-      mtd->_erase = spi_nor_erase;
+       mtd->_read = spi_nor_read;
+       mtd->_suspend = spi_nor_suspend;
+       mtd->_resume = spi_nor_resume;
+@@ -3178,6 +3177,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
+       if (info->flags & SPI_NOR_NO_ERASE)
+               mtd->flags |= MTD_NO_ERASE;
++      else
++              mtd->_erase = spi_nor_erase;
+       mtd->dev.parent = dev;
+       nor->page_size = nor->params->page_size;
+-- 
+2.35.1
+
diff --git a/queue-5.15/net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch b/queue-5.15/net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch
new file mode 100644 (file)
index 0000000..bb73911
--- /dev/null
@@ -0,0 +1,56 @@
+From 269beb92fc9bab7c88951328ee1bc09fd9a01cea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Aug 2021 09:38:32 +0300
+Subject: net/mlx5e: Check action fwd/drop flag exists also for nic flows
+
+From: Roi Dayan <roid@nvidia.com>
+
+[ Upstream commit 6b50cf45b6a0e99f3cab848a72ecca8da56b7460 ]
+
+The driver should add offloaded rules with either a fwd or drop action.
+The check existed in parsing fdb flows but not when parsing nic flows.
+Move the test into actions_match_supported() which is called for
+checking nic flows and fdb flows.
+
+Signed-off-by: Roi Dayan <roid@nvidia.com>
+Reviewed-by: Maor Dickman <maord@nvidia.com>
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index 3aa8d0b83d10..fe52db591121 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -3305,6 +3305,12 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
+       ct_flow = flow_flag_test(flow, CT) && !ct_clear;
+       actions = flow->attr->action;
++      if (!(actions &
++            (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
++              NL_SET_ERR_MSG_MOD(extack, "Rule must have at least one forward/drop action");
++              return false;
++      }
++
+       if (mlx5e_is_eswitch_flow(flow)) {
+               if (flow->attr->esw_attr->split_count && ct_flow &&
+                   !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) {
+@@ -4207,13 +4213,6 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
+               attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       }
+-      if (!(attr->action &
+-            (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+-              NL_SET_ERR_MSG_MOD(extack,
+-                                 "Rule must have at least one forward/drop action");
+-              return -EOPNOTSUPP;
+-      }
+-
+       if (esw_attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "current firmware doesn't support split rule for port mirroring");
+-- 
+2.35.1
+
diff --git a/queue-5.15/net-mlx5e-split-actions_match_supported-into-a-sub-f.patch b/queue-5.15/net-mlx5e-split-actions_match_supported-into-a-sub-f.patch
new file mode 100644 (file)
index 0000000..d7a72c2
--- /dev/null
@@ -0,0 +1,111 @@
+From c6628b78c8f999589ec6a630d9e6222ef2d22cad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Aug 2021 12:53:13 +0300
+Subject: net/mlx5e: Split actions_match_supported() into a sub function
+
+From: Roi Dayan <roid@nvidia.com>
+
+[ Upstream commit 9c1d3511a2c2fd30c991a20c670991ece4ef27c1 ]
+
+There will probably be more checks, some for nic flows, some for fdb
+flows and some are shared checks. Split it for fdb and nic to avoid
+the function getting too big.
+
+Signed-off-by: Roi Dayan <roid@nvidia.com>
+Reviewed-by: Maor Dickman <maord@nvidia.com>
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/mellanox/mlx5/core/en_tc.c   | 65 +++++++++++--------
+ 1 file changed, 39 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index fe52db591121..3c6c7801f131 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -3291,19 +3291,41 @@ static bool modify_header_match_supported(struct mlx5e_priv *priv,
+       return true;
+ }
+-static bool actions_match_supported(struct mlx5e_priv *priv,
+-                                  struct flow_action *flow_action,
+-                                  struct mlx5e_tc_flow_parse_attr *parse_attr,
+-                                  struct mlx5e_tc_flow *flow,
+-                                  struct netlink_ext_ack *extack)
++static bool
++actions_match_supported_fdb(struct mlx5e_priv *priv,
++                          struct mlx5e_tc_flow_parse_attr *parse_attr,
++                          struct mlx5e_tc_flow *flow,
++                          struct netlink_ext_ack *extack)
++{
++      bool ct_flow, ct_clear;
++
++      ct_clear = flow->attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR;
++      ct_flow = flow_flag_test(flow, CT) && !ct_clear;
++
++      if (flow->attr->esw_attr->split_count && ct_flow &&
++          !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) {
++              /* All registers used by ct are cleared when using
++               * split rules.
++               */
++              NL_SET_ERR_MSG_MOD(extack, "Can't offload mirroring with action ct");
++              return false;
++      }
++
++      return true;
++}
++
++static bool
++actions_match_supported(struct mlx5e_priv *priv,
++                      struct flow_action *flow_action,
++                      struct mlx5e_tc_flow_parse_attr *parse_attr,
++                      struct mlx5e_tc_flow *flow,
++                      struct netlink_ext_ack *extack)
+ {
+-      bool ct_flow = false, ct_clear = false;
+-      u32 actions;
++      u32 actions = flow->attr->action;
++      bool ct_flow, ct_clear;
+-      ct_clear = flow->attr->ct_attr.ct_action &
+-              TCA_CT_ACT_CLEAR;
++      ct_clear = flow->attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR;
+       ct_flow = flow_flag_test(flow, CT) && !ct_clear;
+-      actions = flow->attr->action;
+       if (!(actions &
+             (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+@@ -3311,23 +3333,14 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
+               return false;
+       }
+-      if (mlx5e_is_eswitch_flow(flow)) {
+-              if (flow->attr->esw_attr->split_count && ct_flow &&
+-                  !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) {
+-                      /* All registers used by ct are cleared when using
+-                       * split rules.
+-                       */
+-                      NL_SET_ERR_MSG_MOD(extack,
+-                                         "Can't offload mirroring with action ct");
+-                      return false;
+-              }
+-      }
++      if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
++          !modify_header_match_supported(priv, &parse_attr->spec, flow_action,
++                                         actions, ct_flow, ct_clear, extack))
++              return false;
+-      if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+-              return modify_header_match_supported(priv, &parse_attr->spec,
+-                                                   flow_action, actions,
+-                                                   ct_flow, ct_clear,
+-                                                   extack);
++      if (mlx5e_is_eswitch_flow(flow) &&
++          !actions_match_supported_fdb(priv, parse_attr, flow, extack))
++              return false;
+       return true;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch b/queue-5.15/net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch
new file mode 100644 (file)
index 0000000..9e92120
--- /dev/null
@@ -0,0 +1,44 @@
+From 08fd7c1aed95d86dba3605427ca0505d0030061d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jan 2022 10:38:02 +0200
+Subject: net/mlx5e: TC, Reject rules with drop and modify hdr action
+
+From: Roi Dayan <roid@nvidia.com>
+
+[ Upstream commit a2446bc77a16cefd27de712d28af2396d6287593 ]
+
+This kind of action is not supported by firmware and generates a
+syndrome.
+
+kernel: mlx5_core 0000:08:00.0: mlx5_cmd_check:777:(pid 102063): SET_FLOW_TABLE_ENTRY(0x936) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0x8708c3)
+
+Fixes: d7e75a325cb2 ("net/mlx5e: Add offloading of E-Switch TC pedit (header re-write) actions")
+Signed-off-by: Roi Dayan <roid@nvidia.com>
+Reviewed-by: Oz Shlomo <ozsh@nvidia.com>
+Reviewed-by: Maor Dickman <maord@nvidia.com>
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index 3c6c7801f131..eb0d9082ccc5 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -3333,6 +3333,12 @@ actions_match_supported(struct mlx5e_priv *priv,
+               return false;
+       }
++      if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
++          actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
++              NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
++              return false;
++      }
++
+       if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+           !modify_header_match_supported(priv, &parse_attr->spec, flow_action,
+                                          actions, ct_flow, ct_clear, extack))
+-- 
+2.35.1
+
diff --git a/queue-5.15/net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch b/queue-5.15/net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch
new file mode 100644 (file)
index 0000000..9c60f19
--- /dev/null
@@ -0,0 +1,41 @@
+From 2fed603288ae5b4a36ffa1f1c31b209d5c0621ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Jan 2022 15:00:30 +0200
+Subject: net/mlx5e: TC, Reject rules with forward and drop actions
+
+From: Roi Dayan <roid@nvidia.com>
+
+[ Upstream commit 5623ef8a118838aae65363750dfafcba734dc8cb ]
+
+Such rules are redundant but allowed and passed to the driver.
+The driver does not support offloading such rules so return an error.
+
+Fixes: 03a9d11e6eeb ("net/mlx5e: Add TC drop and mirred/redirect action parsing for SRIOV offloads")
+Signed-off-by: Roi Dayan <roid@nvidia.com>
+Reviewed-by: Oz Shlomo <ozsh@nvidia.com>
+Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index eb0d9082ccc5..843c8435387f 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -3333,6 +3333,12 @@ actions_match_supported(struct mlx5e_priv *priv,
+               return false;
+       }
++      if (!(~actions &
++            (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
++              NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action");
++              return false;
++      }
++
+       if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+           actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
+               NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
+-- 
+2.35.1
+
diff --git a/queue-5.15/netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch b/queue-5.15/netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch
new file mode 100644 (file)
index 0000000..54cc01b
--- /dev/null
@@ -0,0 +1,191 @@
+From ca8bc50489444e634dbff70523538a7b959d2656 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Oct 2021 21:47:55 +0200
+Subject: netfilter: nf_tables: convert pktinfo->tprot_set to flags field
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit b5bdc6f9c24db9a0adf8bd00c0e935b184654f00 ]
+
+Generalize boolean field to store more flags on the pktinfo structure.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h      | 8 ++++++--
+ include/net/netfilter/nf_tables_ipv4.h | 7 ++++---
+ include/net/netfilter/nf_tables_ipv6.h | 6 +++---
+ net/netfilter/nf_tables_core.c         | 2 +-
+ net/netfilter/nf_tables_trace.c        | 4 ++--
+ net/netfilter/nft_meta.c               | 2 +-
+ net/netfilter/nft_payload.c            | 4 ++--
+ 7 files changed, 19 insertions(+), 14 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 2af1c2c64128..d005f87691da 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -21,10 +21,14 @@ struct module;
+ #define NFT_JUMP_STACK_SIZE   16
++enum {
++      NFT_PKTINFO_L4PROTO     = (1 << 0),
++};
++
+ struct nft_pktinfo {
+       struct sk_buff                  *skb;
+       const struct nf_hook_state      *state;
+-      bool                            tprot_set;
++      u8                              flags;
+       u8                              tprot;
+       u16                             fragoff;
+       unsigned int                    thoff;
+@@ -75,7 +79,7 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
+ static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt)
+ {
+-      pkt->tprot_set = false;
++      pkt->flags = 0;
+       pkt->tprot = 0;
+       pkt->thoff = 0;
+       pkt->fragoff = 0;
+diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h
+index eb4c094cd54d..c4a6147b0ef8 100644
+--- a/include/net/netfilter/nf_tables_ipv4.h
++++ b/include/net/netfilter/nf_tables_ipv4.h
+@@ -10,7 +10,7 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt)
+       struct iphdr *ip;
+       ip = ip_hdr(pkt->skb);
+-      pkt->tprot_set = true;
++      pkt->flags = NFT_PKTINFO_L4PROTO;
+       pkt->tprot = ip->protocol;
+       pkt->thoff = ip_hdrlen(pkt->skb);
+       pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+@@ -36,7 +36,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
+       else if (len < thoff)
+               return -1;
+-      pkt->tprot_set = true;
++      pkt->flags = NFT_PKTINFO_L4PROTO;
+       pkt->tprot = iph->protocol;
+       pkt->thoff = thoff;
+       pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
+@@ -71,7 +71,7 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
+               goto inhdr_error;
+       }
+-      pkt->tprot_set = true;
++      pkt->flags = NFT_PKTINFO_L4PROTO;
+       pkt->tprot = iph->protocol;
+       pkt->thoff = thoff;
+       pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
+@@ -82,4 +82,5 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
+       __IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INHDRERRORS);
+       return -1;
+ }
++
+ #endif
+diff --git a/include/net/netfilter/nf_tables_ipv6.h b/include/net/netfilter/nf_tables_ipv6.h
+index 7595e02b00ba..ec7eaeaf4f04 100644
+--- a/include/net/netfilter/nf_tables_ipv6.h
++++ b/include/net/netfilter/nf_tables_ipv6.h
+@@ -18,7 +18,7 @@ static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt)
+               return;
+       }
+-      pkt->tprot_set = true;
++      pkt->flags = NFT_PKTINFO_L4PROTO;
+       pkt->tprot = protohdr;
+       pkt->thoff = thoff;
+       pkt->fragoff = frag_off;
+@@ -50,7 +50,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
+       if (protohdr < 0)
+               return -1;
+-      pkt->tprot_set = true;
++      pkt->flags = NFT_PKTINFO_L4PROTO;
+       pkt->tprot = protohdr;
+       pkt->thoff = thoff;
+       pkt->fragoff = frag_off;
+@@ -96,7 +96,7 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt)
+       if (protohdr < 0)
+               goto inhdr_error;
+-      pkt->tprot_set = true;
++      pkt->flags = NFT_PKTINFO_L4PROTO;
+       pkt->tprot = protohdr;
+       pkt->thoff = thoff;
+       pkt->fragoff = frag_off;
+diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
+index 907e848dbc17..d4d8f613af51 100644
+--- a/net/netfilter/nf_tables_core.c
++++ b/net/netfilter/nf_tables_core.c
+@@ -79,7 +79,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
+       if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
+               ptr = skb_network_header(skb);
+       else {
+-              if (!pkt->tprot_set)
++              if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+                       return false;
+               ptr = skb_network_header(skb) + nft_thoff(pkt);
+       }
+diff --git a/net/netfilter/nf_tables_trace.c b/net/netfilter/nf_tables_trace.c
+index e4fe2f0780eb..84a7dea46efa 100644
+--- a/net/netfilter/nf_tables_trace.c
++++ b/net/netfilter/nf_tables_trace.c
+@@ -113,13 +113,13 @@ static int nf_trace_fill_pkt_info(struct sk_buff *nlskb,
+       int off = skb_network_offset(skb);
+       unsigned int len, nh_end;
+-      nh_end = pkt->tprot_set ? nft_thoff(pkt) : skb->len;
++      nh_end = pkt->flags & NFT_PKTINFO_L4PROTO ? nft_thoff(pkt) : skb->len;
+       len = min_t(unsigned int, nh_end - skb_network_offset(skb),
+                   NFT_TRACETYPE_NETWORK_HSIZE);
+       if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len))
+               return -1;
+-      if (pkt->tprot_set) {
++      if (pkt->flags & NFT_PKTINFO_L4PROTO) {
+               len = min_t(unsigned int, skb->len - nft_thoff(pkt),
+                           NFT_TRACETYPE_TRANSPORT_HSIZE);
+               if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
+diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
+index 44d9b38e5f90..14412f69a34e 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -321,7 +321,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
+               nft_reg_store8(dest, nft_pf(pkt));
+               break;
+       case NFT_META_L4PROTO:
+-              if (!pkt->tprot_set)
++              if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+                       goto err;
+               nft_reg_store8(dest, pkt->tprot);
+               break;
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index 132875cd7fff..c3ccfff54a35 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -108,7 +108,7 @@ void nft_payload_eval(const struct nft_expr *expr,
+               offset = skb_network_offset(skb);
+               break;
+       case NFT_PAYLOAD_TRANSPORT_HEADER:
+-              if (!pkt->tprot_set)
++              if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+                       goto err;
+               offset = nft_thoff(pkt);
+               break;
+@@ -613,7 +613,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+               offset = skb_network_offset(skb);
+               break;
+       case NFT_PAYLOAD_TRANSPORT_HEADER:
+-              if (!pkt->tprot_set)
++              if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+                       goto err;
+               offset = nft_thoff(pkt);
+               break;
+-- 
+2.35.1
+
diff --git a/queue-5.15/netfilter-nft_payload-don-t-allow-th-access-for-frag.patch b/queue-5.15/netfilter-nft_payload-don-t-allow-th-access-for-frag.patch
new file mode 100644 (file)
index 0000000..559f180
--- /dev/null
@@ -0,0 +1,81 @@
+From 35ed055b5b815f497a91408e24c2b526d2cdd364 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 29 Jan 2022 17:13:23 +0100
+Subject: netfilter: nft_payload: don't allow th access for fragments
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit a9e8503def0fd4ed89ade1f61c315f904581d439 ]
+
+Loads relative to ->thoff naturally expect that this points to the
+transport header, but this is only true if pkt->fragoff == 0.
+
+This has little effect for rulesets with connection tracking/nat because
+these enable ip defra. For other rulesets this prevents false matches.
+
+Fixes: 96518518cc41 ("netfilter: add nftables")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nft_exthdr.c  | 2 +-
+ net/netfilter/nft_payload.c | 9 +++++----
+ 2 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
+index dbe1f2e7dd9e..9e927ab4df15 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -167,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
+ {
+       struct tcphdr *tcph;
+-      if (pkt->tprot != IPPROTO_TCP)
++      if (pkt->tprot != IPPROTO_TCP || pkt->fragoff)
+               return NULL;
+       tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer);
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index ee359a4a60f5..b46e01365bd9 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -84,7 +84,7 @@ static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
+ {
+       unsigned int thoff = nft_thoff(pkt);
+-      if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
++      if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
+               return -1;
+       switch (pkt->tprot) {
+@@ -148,7 +148,7 @@ void nft_payload_eval(const struct nft_expr *expr,
+               offset = skb_network_offset(skb);
+               break;
+       case NFT_PAYLOAD_TRANSPORT_HEADER:
+-              if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
++              if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
+                       goto err;
+               offset = nft_thoff(pkt);
+               break;
+@@ -658,7 +658,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+               offset = skb_network_offset(skb);
+               break;
+       case NFT_PAYLOAD_TRANSPORT_HEADER:
+-              if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
++              if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
+                       goto err;
+               offset = nft_thoff(pkt);
+               break;
+@@ -697,7 +697,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+       if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
+           pkt->tprot == IPPROTO_SCTP &&
+           skb->ip_summed != CHECKSUM_PARTIAL) {
+-              if (nft_payload_csum_sctp(skb, nft_thoff(pkt)))
++              if (pkt->fragoff == 0 &&
++                  nft_payload_csum_sctp(skb, nft_thoff(pkt)))
+                       goto err;
+       }
+-- 
+2.35.1
+
diff --git a/queue-5.15/netfilter-nft_payload-support-for-inner-header-match.patch b/queue-5.15/netfilter-nft_payload-support-for-inner-header-match.patch
new file mode 100644 (file)
index 0000000..8ebe308
--- /dev/null
@@ -0,0 +1,172 @@
+From 78c276321cd1b4cb114ebdebe38bd97c4768824a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Oct 2021 22:15:00 +0200
+Subject: netfilter: nft_payload: support for inner header matching / mangling
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit c46b38dc8743535e686b911d253a844f0bd50ead ]
+
+Allow to match and mangle on inner headers / payload data after the
+transport header. There is a new field in the pktinfo structure that
+stores the inner header offset which is calculated only when requested.
+Only TCP and UDP supported at this stage.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h        |  2 +
+ include/uapi/linux/netfilter/nf_tables.h |  2 +
+ net/netfilter/nft_payload.c              | 56 +++++++++++++++++++++++-
+ 3 files changed, 58 insertions(+), 2 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index d005f87691da..bcfee89012a1 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -23,6 +23,7 @@ struct module;
+ enum {
+       NFT_PKTINFO_L4PROTO     = (1 << 0),
++      NFT_PKTINFO_INNER       = (1 << 1),
+ };
+ struct nft_pktinfo {
+@@ -32,6 +33,7 @@ struct nft_pktinfo {
+       u8                              tprot;
+       u16                             fragoff;
+       unsigned int                    thoff;
++      unsigned int                    inneroff;
+ };
+ static inline struct sock *nft_sk(const struct nft_pktinfo *pkt)
+diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
+index e94d1fa554cb..07871c8a0601 100644
+--- a/include/uapi/linux/netfilter/nf_tables.h
++++ b/include/uapi/linux/netfilter/nf_tables.h
+@@ -753,11 +753,13 @@ enum nft_dynset_attributes {
+  * @NFT_PAYLOAD_LL_HEADER: link layer header
+  * @NFT_PAYLOAD_NETWORK_HEADER: network header
+  * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
++ * @NFT_PAYLOAD_INNER_HEADER: inner header / payload
+  */
+ enum nft_payload_bases {
+       NFT_PAYLOAD_LL_HEADER,
+       NFT_PAYLOAD_NETWORK_HEADER,
+       NFT_PAYLOAD_TRANSPORT_HEADER,
++      NFT_PAYLOAD_INNER_HEADER,
+ };
+ /**
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index c3ccfff54a35..ee359a4a60f5 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -22,6 +22,7 @@
+ #include <linux/icmpv6.h>
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
++#include <linux/ip.h>
+ #include <net/sctp/checksum.h>
+ static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
+@@ -79,6 +80,45 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
+       return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0;
+ }
++static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
++{
++      unsigned int thoff = nft_thoff(pkt);
++
++      if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
++              return -1;
++
++      switch (pkt->tprot) {
++      case IPPROTO_UDP:
++              pkt->inneroff = thoff + sizeof(struct udphdr);
++              break;
++      case IPPROTO_TCP: {
++              struct tcphdr *th, _tcph;
++
++              th = skb_header_pointer(pkt->skb, thoff, sizeof(_tcph), &_tcph);
++              if (!th)
++                      return -1;
++
++              pkt->inneroff = thoff + __tcp_hdrlen(th);
++              }
++              break;
++      default:
++              return -1;
++      }
++
++      pkt->flags |= NFT_PKTINFO_INNER;
++
++      return 0;
++}
++
++static int nft_payload_inner_offset(const struct nft_pktinfo *pkt)
++{
++      if (!(pkt->flags & NFT_PKTINFO_INNER) &&
++          __nft_payload_inner_offset((struct nft_pktinfo *)pkt) < 0)
++              return -1;
++
++      return pkt->inneroff;
++}
++
+ void nft_payload_eval(const struct nft_expr *expr,
+                     struct nft_regs *regs,
+                     const struct nft_pktinfo *pkt)
+@@ -112,6 +152,11 @@ void nft_payload_eval(const struct nft_expr *expr,
+                       goto err;
+               offset = nft_thoff(pkt);
+               break;
++      case NFT_PAYLOAD_INNER_HEADER:
++              offset = nft_payload_inner_offset(pkt);
++              if (offset < 0)
++                      goto err;
++              break;
+       default:
+               BUG();
+       }
+@@ -617,6 +662,11 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+                       goto err;
+               offset = nft_thoff(pkt);
+               break;
++      case NFT_PAYLOAD_INNER_HEADER:
++              offset = nft_payload_inner_offset(pkt);
++              if (offset < 0)
++                      goto err;
++              break;
+       default:
+               BUG();
+       }
+@@ -625,7 +675,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+       offset += priv->offset;
+       if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
+-          (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
++          ((priv->base != NFT_PAYLOAD_TRANSPORT_HEADER &&
++            priv->base != NFT_PAYLOAD_INNER_HEADER) ||
+            skb->ip_summed != CHECKSUM_PARTIAL)) {
+               fsum = skb_checksum(skb, offset, priv->len, 0);
+               tsum = csum_partial(src, priv->len, 0);
+@@ -744,6 +795,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
+       case NFT_PAYLOAD_LL_HEADER:
+       case NFT_PAYLOAD_NETWORK_HEADER:
+       case NFT_PAYLOAD_TRANSPORT_HEADER:
++      case NFT_PAYLOAD_INNER_HEADER:
+               break;
+       default:
+               return ERR_PTR(-EOPNOTSUPP);
+@@ -762,7 +814,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
+       len    = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
+       if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
+-          base != NFT_PAYLOAD_LL_HEADER)
++          base != NFT_PAYLOAD_LL_HEADER && base != NFT_PAYLOAD_INNER_HEADER)
+               return &nft_payload_fast_ops;
+       else
+               return &nft_payload_ops;
+-- 
+2.35.1
+
diff --git a/queue-5.15/nfsd-commit-operations-must-not-return-nfs-err_inval.patch b/queue-5.15/nfsd-commit-operations-must-not-return-nfs-err_inval.patch
new file mode 100644 (file)
index 0000000..5ac253a
--- /dev/null
@@ -0,0 +1,180 @@
+From ee4b59358b00686f1bf54c9e8dc579fa7c6f8379 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Jan 2022 15:50:31 -0500
+Subject: NFSD: COMMIT operations must not return NFS?ERR_INVAL
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 3f965021c8bc38965ecb1924f570c4842b33d408 ]
+
+Since, well, forever, the Linux NFS server's nfsd_commit() function
+has returned nfserr_inval when the passed-in byte range arguments
+were non-sensical.
+
+However, according to RFC 1813 section 3.3.21, NFSv3 COMMIT requests
+are permitted to return only the following non-zero status codes:
+
+      NFS3ERR_IO
+      NFS3ERR_STALE
+      NFS3ERR_BADHANDLE
+      NFS3ERR_SERVERFAULT
+
+NFS3ERR_INVAL is not included in that list. Likewise, NFS4ERR_INVAL
+is not listed in the COMMIT row of Table 6 in RFC 8881.
+
+RFC 7530 does permit COMMIT to return NFS4ERR_INVAL, but does not
+specify when it can or should be used.
+
+Instead of dropping or failing a COMMIT request in a byte range that
+is not supported, turn it into a valid request by treating one or
+both arguments as zero. Offset zero means start-of-file, count zero
+means until-end-of-file, so we only ever extend the commit range.
+NFS servers are always allowed to commit more and sooner than
+requested.
+
+The range check is no longer bounded by NFS_OFFSET_MAX, but rather
+by the value that is returned in the maxfilesize field of the NFSv3
+FSINFO procedure or the NFSv4 maxfilesize file attribute.
+
+Note that this change results in a new pynfs failure:
+
+CMT4     st_commit.testCommitOverflow                             : RUNNING
+CMT4     st_commit.testCommitOverflow                             : FAILURE
+           COMMIT with offset + count overflow should return
+           NFS4ERR_INVAL, instead got NFS4_OK
+
+IMO the test is not correct as written: RFC 8881 does not allow the
+COMMIT operation to return NFS4ERR_INVAL.
+
+Reported-by: Dan Aloni <dan.aloni@vastdata.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Bruce Fields <bfields@fieldses.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs3proc.c |  6 ------
+ fs/nfsd/vfs.c      | 53 +++++++++++++++++++++++++++++++---------------
+ fs/nfsd/vfs.h      |  4 ++--
+ 3 files changed, 38 insertions(+), 25 deletions(-)
+
+diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
+index b540489ea240..936eebd4c56d 100644
+--- a/fs/nfsd/nfs3proc.c
++++ b/fs/nfsd/nfs3proc.c
+@@ -660,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
+                               argp->count,
+                               (unsigned long long) argp->offset);
+-      if (argp->offset > NFS_OFFSET_MAX) {
+-              resp->status = nfserr_inval;
+-              goto out;
+-      }
+-
+       fh_copy(&resp->fh, &argp->fh);
+       resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
+                                  argp->count, resp->verf);
+-out:
+       return rpc_success;
+ }
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index c8e3f81d110e..abfbb6953e89 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1108,42 +1108,61 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
+ }
+ #ifdef CONFIG_NFSD_V3
+-/*
+- * Commit all pending writes to stable storage.
++/**
++ * nfsd_commit - Commit pending writes to stable storage
++ * @rqstp: RPC request being processed
++ * @fhp: NFS filehandle
++ * @offset: raw offset from beginning of file
++ * @count: raw count of bytes to sync
++ * @verf: filled in with the server's current write verifier
+  *
+- * Note: we only guarantee that data that lies within the range specified
+- * by the 'offset' and 'count' parameters will be synced.
++ * Note: we guarantee that data that lies within the range specified
++ * by the 'offset' and 'count' parameters will be synced. The server
++ * is permitted to sync data that lies outside this range at the
++ * same time.
+  *
+  * Unfortunately we cannot lock the file to make sure we return full WCC
+  * data to the client, as locking happens lower down in the filesystem.
++ *
++ * Return values:
++ *   An nfsstat value in network byte order.
+  */
+ __be32
+-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-               loff_t offset, unsigned long count, __be32 *verf)
++nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
++          u32 count, __be32 *verf)
+ {
++      u64                     maxbytes;
++      loff_t                  start, end;
+       struct nfsd_net         *nn;
+       struct nfsd_file        *nf;
+-      loff_t                  end = LLONG_MAX;
+-      __be32                  err = nfserr_inval;
+-
+-      if (offset < 0)
+-              goto out;
+-      if (count != 0) {
+-              end = offset + (loff_t)count - 1;
+-              if (end < offset)
+-                      goto out;
+-      }
++      __be32                  err;
+       err = nfsd_file_acquire(rqstp, fhp,
+                       NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
+       if (err)
+               goto out;
++
++      /*
++       * Convert the client-provided (offset, count) range to a
++       * (start, end) range. If the client-provided range falls
++       * outside the maximum file size of the underlying FS,
++       * clamp the sync range appropriately.
++       */
++      start = 0;
++      end = LLONG_MAX;
++      maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes;
++      if (offset < maxbytes) {
++              start = offset;
++              if (count && (offset + count - 1 < maxbytes))
++                      end = offset + count - 1;
++      }
++
+       nn = net_generic(nf->nf_net, nfsd_net_id);
+       if (EX_ISSYNC(fhp->fh_export)) {
+               errseq_t since = READ_ONCE(nf->nf_file->f_wb_err);
+               int err2;
+-              err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
++              err2 = vfs_fsync_range(nf->nf_file, start, end, 0);
+               switch (err2) {
+               case 0:
+                       nfsd_copy_boot_verifier(verf, nn);
+diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
+index b21b76e6b9a8..3cf5a8a13da5 100644
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -73,8 +73,8 @@ __be32               do_nfsd_create(struct svc_rqst *, struct svc_fh *,
+                               char *name, int len, struct iattr *attrs,
+                               struct svc_fh *res, int createmode,
+                               u32 *verifier, bool *truncp, bool *created);
+-__be32                nfsd_commit(struct svc_rqst *, struct svc_fh *,
+-                              loff_t, unsigned long, __be32 *verf);
++__be32                nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
++                              u64 offset, u32 count, __be32 *verf);
+ #endif /* CONFIG_NFSD_V3 */
+ #ifdef CONFIG_NFSD_V4
+ __be32                nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-- 
+2.35.1
+
diff --git a/queue-5.15/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch b/queue-5.15/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch
new file mode 100644 (file)
index 0000000..03034be
--- /dev/null
@@ -0,0 +1,66 @@
+From bf108ea172027ce18c12db5a722943ad666d2583 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Dec 2021 14:26:03 -0500
+Subject: NFSD: De-duplicate net_generic(nf->nf_net, nfsd_net_id)
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 2c445a0e72cb1fbfbdb7f9473c53556ee27c1d90 ]
+
+Since this pointer is used repeatedly, move it to a stack variable.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/vfs.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index 5f62fa0963ce..c8e3f81d110e 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1121,6 +1121,7 @@ __be32
+ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                loff_t offset, unsigned long count, __be32 *verf)
+ {
++      struct nfsd_net         *nn;
+       struct nfsd_file        *nf;
+       loff_t                  end = LLONG_MAX;
+       __be32                  err = nfserr_inval;
+@@ -1137,6 +1138,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                       NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
+       if (err)
+               goto out;
++      nn = net_generic(nf->nf_net, nfsd_net_id);
+       if (EX_ISSYNC(fhp->fh_export)) {
+               errseq_t since = READ_ONCE(nf->nf_file->f_wb_err);
+               int err2;
+@@ -1144,8 +1146,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
+               switch (err2) {
+               case 0:
+-                      nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
+-                                              nfsd_net_id));
++                      nfsd_copy_boot_verifier(verf, nn);
+                       err2 = filemap_check_wb_err(nf->nf_file->f_mapping,
+                                                   since);
+                       err = nfserrno(err2);
+@@ -1154,13 +1155,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                       err = nfserr_notsupp;
+                       break;
+               default:
+-                      nfsd_reset_boot_verifier(net_generic(nf->nf_net,
+-                                               nfsd_net_id));
++                      nfsd_reset_boot_verifier(nn);
+                       err = nfserrno(err2);
+               }
+       } else
+-              nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
+-                                      nfsd_net_id));
++              nfsd_copy_boot_verifier(verf, nn);
+       nfsd_file_put(nf);
+ out:
+-- 
+2.35.1
+
diff --git a/queue-5.15/pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch b/queue-5.15/pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch
new file mode 100644 (file)
index 0000000..2bb4bc8
--- /dev/null
@@ -0,0 +1,179 @@
+From cef53b5144e8e5932507f993c499987da65b7324 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 31 Jul 2021 14:39:01 +0200
+Subject: PCI: pciehp: Ignore Link Down/Up caused by error-induced Hot Reset
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit ea401499e943c307e6d44af6c2b4e068643e7884 ]
+
+Stuart Hayes reports that an error handled by DPC at a Root Port results
+in pciehp gratuitously bringing down a subordinate hotplug port:
+
+  RP -- UP -- DP -- UP -- DP (hotplug) -- EP
+
+pciehp brings the slot down because the Link to the Endpoint goes down.
+That is caused by a Hot Reset being propagated as a result of DPC.
+Per PCIe Base Spec 5.0, section 6.6.1 "Conventional Reset":
+
+  For a Switch, the following must cause a hot reset to be sent on all
+  Downstream Ports: [...]
+
+  * The Data Link Layer of the Upstream Port reporting DL_Down status.
+    In Switches that support Link speeds greater than 5.0 GT/s, the
+    Upstream Port must direct the LTSSM of each Downstream Port to the
+    Hot Reset state, but not hold the LTSSMs in that state. This permits
+    each Downstream Port to begin Link training immediately after its
+    hot reset completes. This behavior is recommended for all Switches.
+
+  * Receiving a hot reset on the Upstream Port.
+
+Once DPC recovers, pcie_do_recovery() walks down the hierarchy and
+invokes pcie_portdrv_slot_reset() to restore each port's config space.
+At that point, a hotplug interrupt is signaled per PCIe Base Spec r5.0,
+section 6.7.3.4 "Software Notification of Hot-Plug Events":
+
+  If the Port is enabled for edge-triggered interrupt signaling using
+  MSI or MSI-X, an interrupt message must be sent every time the logical
+  AND of the following conditions transitions from FALSE to TRUE: [...]
+
+  * The Hot-Plug Interrupt Enable bit in the Slot Control register is
+    set to 1b.
+
+  * At least one hot-plug event status bit in the Slot Status register
+    and its associated enable bit in the Slot Control register are both
+    set to 1b.
+
+Prevent pciehp from gratuitously bringing down the slot by clearing the
+error-induced Data Link Layer State Changed event before restoring
+config space.  Afterwards, check whether the link has unexpectedly
+failed to retrain and synthesize a DLLSC event if so.
+
+Allow each pcie_port_service_driver (one of them being pciehp) to define
+a slot_reset callback and re-use the existing pm_iter() function to
+iterate over the callbacks.
+
+Thereby, the Endpoint driver remains bound throughout error recovery and
+may restore the device to working state.
+
+Surprise removal during error recovery is detected through a Presence
+Detect Changed event.  The hotplug port is expected to not signal that
+event as a result of a Hot Reset.
+
+The issue isn't DPC-specific, it also occurs when an error is handled by
+AER through aer_root_reset().  So while the issue was noticed only now,
+it's been around since 2006 when AER support was first introduced.
+
+[bhelgaas: drop PCI_ERROR_RECOVERY Kconfig, split pm_iter() rename to
+preparatory patch]
+Link: https://lore.kernel.org/linux-pci/08c046b0-c9f2-3489-eeef-7e7aca435bb9@gmail.com/
+Fixes: 6c2b374d7485 ("PCI-Express AER implemetation: AER core and aerdriver")
+Link: https://lore.kernel.org/r/251f4edcc04c14f873ff1c967bc686169cd07d2d.1627638184.git.lukas@wunner.de
+Reported-by: Stuart Hayes <stuart.w.hayes@gmail.com>
+Tested-by: Stuart Hayes <stuart.w.hayes@gmail.com>
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org # v2.6.19+: ba952824e6c1: PCI/portdrv: Report reset for frozen channel
+Cc: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/hotplug/pciehp.h      |  2 ++
+ drivers/pci/hotplug/pciehp_core.c |  2 ++
+ drivers/pci/hotplug/pciehp_hpc.c  | 26 ++++++++++++++++++++++++++
+ drivers/pci/pcie/portdrv.h        |  2 ++
+ drivers/pci/pcie/portdrv_pci.c    |  3 +++
+ 5 files changed, 35 insertions(+)
+
+diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
+index 10d7e7e1b553..e0a614acee05 100644
+--- a/drivers/pci/hotplug/pciehp.h
++++ b/drivers/pci/hotplug/pciehp.h
+@@ -192,6 +192,8 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status);
+ int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
+ int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
++int pciehp_slot_reset(struct pcie_device *dev);
++
+ static inline const char *slot_name(struct controller *ctrl)
+ {
+       return hotplug_slot_name(&ctrl->hotplug_slot);
+diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
+index e7fe4b42f039..4042d87d539d 100644
+--- a/drivers/pci/hotplug/pciehp_core.c
++++ b/drivers/pci/hotplug/pciehp_core.c
+@@ -351,6 +351,8 @@ static struct pcie_port_service_driver hpdriver_portdrv = {
+       .runtime_suspend = pciehp_runtime_suspend,
+       .runtime_resume = pciehp_runtime_resume,
+ #endif        /* PM */
++
++      .slot_reset     = pciehp_slot_reset,
+ };
+ int __init pcie_hp_init(void)
+diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
+index 8bedbc77fe95..60098a701e83 100644
+--- a/drivers/pci/hotplug/pciehp_hpc.c
++++ b/drivers/pci/hotplug/pciehp_hpc.c
+@@ -865,6 +865,32 @@ void pcie_disable_interrupt(struct controller *ctrl)
+       pcie_write_cmd(ctrl, 0, mask);
+ }
++/**
++ * pciehp_slot_reset() - ignore link event caused by error-induced hot reset
++ * @dev: PCI Express port service device
++ *
++ * Called from pcie_portdrv_slot_reset() after AER or DPC initiated a reset
++ * further up in the hierarchy to recover from an error.  The reset was
++ * propagated down to this hotplug port.  Ignore the resulting link flap.
++ * If the link failed to retrain successfully, synthesize the ignored event.
++ * Surprise removal during reset is detected through Presence Detect Changed.
++ */
++int pciehp_slot_reset(struct pcie_device *dev)
++{
++      struct controller *ctrl = get_service_data(dev);
++
++      if (ctrl->state != ON_STATE)
++              return 0;
++
++      pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA,
++                                 PCI_EXP_SLTSTA_DLLSC);
++
++      if (!pciehp_check_link_active(ctrl))
++              pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
++
++      return 0;
++}
++
+ /*
+  * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
+  * bus reset of the bridge, but at the same time we want to ensure that it is
+diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
+index 6126ee4676a7..41fe1ffd5907 100644
+--- a/drivers/pci/pcie/portdrv.h
++++ b/drivers/pci/pcie/portdrv.h
+@@ -85,6 +85,8 @@ struct pcie_port_service_driver {
+       int (*runtime_suspend)(struct pcie_device *dev);
+       int (*runtime_resume)(struct pcie_device *dev);
++      int (*slot_reset)(struct pcie_device *dev);
++
+       /* Device driver may resume normal operations */
+       void (*error_resume)(struct pci_dev *dev);
+diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
+index c7ff1eea225a..1af74c3d9d5d 100644
+--- a/drivers/pci/pcie/portdrv_pci.c
++++ b/drivers/pci/pcie/portdrv_pci.c
+@@ -160,6 +160,9 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
+ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
+ {
++      size_t off = offsetof(struct pcie_port_service_driver, slot_reset);
++      device_for_each_child(&dev->dev, &off, pcie_port_device_iter);
++
+       pci_restore_state(dev);
+       pci_save_state(dev);
+       return PCI_ERS_RESULT_RECOVERED;
+-- 
+2.35.1
+
diff --git a/queue-5.15/pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch b/queue-5.15/pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch
new file mode 100644 (file)
index 0000000..e35680d
--- /dev/null
@@ -0,0 +1,116 @@
+From a9a4c4fae3732ed658c04f1d51892e4569f57dc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Oct 2021 13:58:40 -0500
+Subject: PCI/portdrv: Rename pm_iter() to pcie_port_device_iter()
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit 3134689f98f9e09004a4727370adc46e7635b4be ]
+
+Rename pm_iter() to pcie_port_device_iter() and make it visible outside
+CONFIG_PM and portdrv_core.c so it can be used for pciehp slot reset
+recovery.
+
+[bhelgaas: split into its own patch]
+Link: https://lore.kernel.org/linux-pci/08c046b0-c9f2-3489-eeef-7e7aca435bb9@gmail.com/
+Link: https://lore.kernel.org/r/251f4edcc04c14f873ff1c967bc686169cd07d2d.1627638184.git.lukas@wunner.de
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/portdrv.h      |  1 +
+ drivers/pci/pcie/portdrv_core.c | 20 ++++++++++----------
+ 2 files changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
+index 2ff5724b8f13..6126ee4676a7 100644
+--- a/drivers/pci/pcie/portdrv.h
++++ b/drivers/pci/pcie/portdrv.h
+@@ -110,6 +110,7 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *new);
+ extern struct bus_type pcie_port_bus_type;
+ int pcie_port_device_register(struct pci_dev *dev);
++int pcie_port_device_iter(struct device *dev, void *data);
+ #ifdef CONFIG_PM
+ int pcie_port_device_suspend(struct device *dev);
+ int pcie_port_device_resume_noirq(struct device *dev);
+diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
+index 3ee63968deaa..604feeb84ee4 100644
+--- a/drivers/pci/pcie/portdrv_core.c
++++ b/drivers/pci/pcie/portdrv_core.c
+@@ -367,24 +367,24 @@ int pcie_port_device_register(struct pci_dev *dev)
+       return status;
+ }
+-#ifdef CONFIG_PM
+-typedef int (*pcie_pm_callback_t)(struct pcie_device *);
++typedef int (*pcie_callback_t)(struct pcie_device *);
+-static int pm_iter(struct device *dev, void *data)
++int pcie_port_device_iter(struct device *dev, void *data)
+ {
+       struct pcie_port_service_driver *service_driver;
+       size_t offset = *(size_t *)data;
+-      pcie_pm_callback_t cb;
++      pcie_callback_t cb;
+       if ((dev->bus == &pcie_port_bus_type) && dev->driver) {
+               service_driver = to_service_driver(dev->driver);
+-              cb = *(pcie_pm_callback_t *)((void *)service_driver + offset);
++              cb = *(pcie_callback_t *)((void *)service_driver + offset);
+               if (cb)
+                       return cb(to_pcie_device(dev));
+       }
+       return 0;
+ }
++#ifdef CONFIG_PM
+ /**
+  * pcie_port_device_suspend - suspend port services associated with a PCIe port
+  * @dev: PCI Express port to handle
+@@ -392,13 +392,13 @@ static int pm_iter(struct device *dev, void *data)
+ int pcie_port_device_suspend(struct device *dev)
+ {
+       size_t off = offsetof(struct pcie_port_service_driver, suspend);
+-      return device_for_each_child(dev, &off, pm_iter);
++      return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+ int pcie_port_device_resume_noirq(struct device *dev)
+ {
+       size_t off = offsetof(struct pcie_port_service_driver, resume_noirq);
+-      return device_for_each_child(dev, &off, pm_iter);
++      return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+ /**
+@@ -408,7 +408,7 @@ int pcie_port_device_resume_noirq(struct device *dev)
+ int pcie_port_device_resume(struct device *dev)
+ {
+       size_t off = offsetof(struct pcie_port_service_driver, resume);
+-      return device_for_each_child(dev, &off, pm_iter);
++      return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+ /**
+@@ -418,7 +418,7 @@ int pcie_port_device_resume(struct device *dev)
+ int pcie_port_device_runtime_suspend(struct device *dev)
+ {
+       size_t off = offsetof(struct pcie_port_service_driver, runtime_suspend);
+-      return device_for_each_child(dev, &off, pm_iter);
++      return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+ /**
+@@ -428,7 +428,7 @@ int pcie_port_device_runtime_suspend(struct device *dev)
+ int pcie_port_device_runtime_resume(struct device *dev)
+ {
+       size_t off = offsetof(struct pcie_port_service_driver, runtime_resume);
+-      return device_for_each_child(dev, &off, pm_iter);
++      return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+ #endif /* PM */
+-- 
+2.35.1
+
diff --git a/queue-5.15/platform-x86-wmi-fix-driver-notify-vs-probe-race.patch b/queue-5.15/platform-x86-wmi-fix-driver-notify-vs-probe-race.patch
new file mode 100644 (file)
index 0000000..f8e4d7a
--- /dev/null
@@ -0,0 +1,69 @@
+From 4fb1d32679362fbe42c6b51cc7b97aca3c883712 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Nov 2021 20:00:28 +0100
+Subject: platform/x86: wmi: Fix driver->notify() vs ->probe() race
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit 9918878676a5f9e99b98679f04b9e6c0f5426b0a ]
+
+The driver core sets struct device->driver before calling out
+to the bus' probe() method, this leaves a window where an ACPI
+notify may happen on the WMI object before the driver's
+probe() method has completed running, causing e.g. the
+driver's notify() callback to get called with drvdata
+not yet being set leading to a NULL pointer deref.
+
+At a check for this to the WMI core, ensuring that the notify()
+callback is not called before the driver is ready.
+
+Fixes: 1686f5444546 ("platform/x86: wmi: Incorporate acpi_install_notify_handler")
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20211128190031.405620-2-hdegoede@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/wmi.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
+index a00b72ace6d2..c4f917d45b51 100644
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -53,6 +53,7 @@ struct guid_block {
+ enum {        /* wmi_block flags */
+       WMI_READ_TAKES_NO_ARGS,
++      WMI_PROBED,
+ };
+ struct wmi_block {
+@@ -980,6 +981,7 @@ static int wmi_dev_probe(struct device *dev)
+               }
+       }
++      set_bit(WMI_PROBED, &wblock->flags);
+       return 0;
+ probe_misc_failure:
+@@ -997,6 +999,8 @@ 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);
++
+       if (wdriver->filter_callback) {
+               misc_deregister(&wblock->char_dev);
+               kfree(wblock->char_dev.name);
+@@ -1299,7 +1303,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
+               return;
+       /* If a driver is bound, then notify the driver. */
+-      if (wblock->dev.dev.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_object_list input;
+               union acpi_object params[1];
+-- 
+2.35.1
+
diff --git a/queue-5.15/platform-x86-wmi-introduce-helper-to-convert-driver-.patch b/queue-5.15/platform-x86-wmi-introduce-helper-to-convert-driver-.patch
new file mode 100644 (file)
index 0000000..499429a
--- /dev/null
@@ -0,0 +1,101 @@
+From 6179f225e94fd8c93b9612d7c581e9884f24901c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 4 Sep 2021 17:56:32 +0000
+Subject: platform/x86: wmi: introduce helper to convert driver to WMI driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Barnabás PÅ‘cze <pobrn@protonmail.com>
+
+[ Upstream commit e7b2e33449e22fdbaa0247d96f31543affe6163d ]
+
+Introduce a helper function which wraps the appropriate
+`container_of()` macro invocation to convert
+a `struct device_driver` to `struct wmi_driver`.
+
+Signed-off-by: Barnabás PÅ‘cze <pobrn@protonmail.com>
+Link: https://lore.kernel.org/r/20210904175450.156801-27-pobrn@protonmail.com
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/wmi.c | 22 ++++++++++------------
+ 1 file changed, 10 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
+index 1b65bb61ce88..9aeb1a009097 100644
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -676,6 +676,11 @@ static struct wmi_device *dev_to_wdev(struct device *dev)
+       return container_of(dev, struct wmi_device, dev);
+ }
++static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
++{
++      return container_of(drv, struct wmi_driver, driver);
++}
++
+ /*
+  * sysfs interface
+  */
+@@ -794,8 +799,7 @@ static void wmi_dev_release(struct device *dev)
+ static int wmi_dev_match(struct device *dev, struct device_driver *driver)
+ {
+-      struct wmi_driver *wmi_driver =
+-              container_of(driver, struct wmi_driver, driver);
++      struct wmi_driver *wmi_driver = drv_to_wdrv(driver);
+       struct wmi_block *wblock = dev_to_wblock(dev);
+       const struct wmi_device_id *id = wmi_driver->id_table;
+@@ -892,8 +896,7 @@ static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+       }
+       /* let the driver do any filtering and do the call */
+-      wdriver = container_of(wblock->dev.dev.driver,
+-                             struct wmi_driver, driver);
++      wdriver = drv_to_wdrv(wblock->dev.dev.driver);
+       if (!try_module_get(wdriver->driver.owner)) {
+               ret = -EBUSY;
+               goto out_ioctl;
+@@ -926,8 +929,7 @@ static const struct file_operations wmi_fops = {
+ static int wmi_dev_probe(struct device *dev)
+ {
+       struct wmi_block *wblock = dev_to_wblock(dev);
+-      struct wmi_driver *wdriver =
+-              container_of(dev->driver, struct wmi_driver, driver);
++      struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
+       int ret = 0;
+       char *buf;
+@@ -990,8 +992,7 @@ static int wmi_dev_probe(struct device *dev)
+ static void wmi_dev_remove(struct device *dev)
+ {
+       struct wmi_block *wblock = dev_to_wblock(dev);
+-      struct wmi_driver *wdriver =
+-              container_of(dev->driver, struct wmi_driver, driver);
++      struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
+       if (wdriver->filter_callback) {
+               misc_deregister(&wblock->char_dev);
+@@ -1296,15 +1297,12 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
+       /* If a driver is bound, then notify the driver. */
+       if (wblock->dev.dev.driver) {
+-              struct wmi_driver *driver;
++              struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);
+               struct acpi_object_list input;
+               union acpi_object params[1];
+               struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL };
+               acpi_status status;
+-              driver = container_of(wblock->dev.dev.driver,
+-                                    struct wmi_driver, driver);
+-
+               input.count = 1;
+               input.pointer = params;
+               params[0].type = ACPI_TYPE_INTEGER;
+-- 
+2.35.1
+
diff --git a/queue-5.15/platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch b/queue-5.15/platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch
new file mode 100644 (file)
index 0000000..82e3edb
--- /dev/null
@@ -0,0 +1,70 @@
+From 607b077f27c8d64adcfc43e25610d69f25a5fd36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Nov 2021 20:00:27 +0100
+Subject: platform/x86: wmi: Replace read_takes_no_args with a flags field
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit a90b38c58667142ecff2521481ed44286d46b140 ]
+
+Replace the wmi_block.read_takes_no_args bool field with
+an unsigned long flags field, used together with test_bit()
+and friends.
+
+This is a preparation patch for fixing a driver->notify() vs ->probe()
+race, which requires atomic flag handling.
+
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20211128190031.405620-1-hdegoede@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/wmi.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
+index 9aeb1a009097..a00b72ace6d2 100644
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -51,6 +51,10 @@ struct guid_block {
+       u8 flags;
+ };
++enum {        /* wmi_block flags */
++      WMI_READ_TAKES_NO_ARGS,
++};
++
+ struct wmi_block {
+       struct wmi_device dev;
+       struct list_head list;
+@@ -61,8 +65,7 @@ struct wmi_block {
+       wmi_notify_handler handler;
+       void *handler_data;
+       u64 req_buf_size;
+-
+-      bool read_takes_no_args;
++      unsigned long flags;
+ };
+@@ -325,7 +328,7 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
+       wq_params[0].type = ACPI_TYPE_INTEGER;
+       wq_params[0].integer.value = instance;
+-      if (instance == 0 && wblock->read_takes_no_args)
++      if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags))
+               input.count = 0;
+       /*
+@@ -1087,7 +1090,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
+        * laptops, WQxx may not be a method at all.)
+        */
+       if (info->type != ACPI_TYPE_METHOD || info->param_count == 0)
+-              wblock->read_takes_no_args = true;
++              set_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags);
+       kfree(info);
+-- 
+2.35.1
+
diff --git a/queue-5.15/powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch b/queue-5.15/powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch
new file mode 100644 (file)
index 0000000..99986d7
--- /dev/null
@@ -0,0 +1,49 @@
+From f1c09f0b31f846a8d0c2ae5ed11258e0a405f3de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Aug 2021 15:29:12 +0000
+Subject: powerpc/32: Don't use lmw/stmw for saving/restoring non volatile regs
+
+From: Christophe Leroy <christophe.leroy@csgroup.eu>
+
+[ Upstream commit a85c728cb5e12216c19ae5878980c2cbbbf8616d ]
+
+Instructions lmw/stmw are interesting for functions that are rarely
+used and not in the cache, because only one instruction is to be
+copied into the instruction cache instead of 19. However those
+instruction are less performant than 19x raw lwz/stw as they require
+synchronisation plus one additional cycle.
+
+SAVE_NVGPRS / REST_NVGPRS are used in only a few places which are
+mostly in interrupts entries/exits and in task switch so they are
+likely already in the cache.
+
+Using standard lwz improves null_syscall selftest by:
+- 10 cycles on mpc832x.
+- 2 cycles on mpc8xx.
+
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/316c543b8906712c108985c8463eec09c8db577b.1629732542.git.christophe.leroy@csgroup.eu
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/ppc_asm.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
+index 1c538a9a11e0..7be24048b8d1 100644
+--- a/arch/powerpc/include/asm/ppc_asm.h
++++ b/arch/powerpc/include/asm/ppc_asm.h
+@@ -28,8 +28,8 @@
+ #else
+ #define SAVE_GPR(n, base)     stw     n,GPR0+4*(n)(base)
+ #define REST_GPR(n, base)     lwz     n,GPR0+4*(n)(base)
+-#define SAVE_NVGPRS(base)     stmw    13, GPR0+4*13(base)
+-#define REST_NVGPRS(base)     lmw     13, GPR0+4*13(base)
++#define SAVE_NVGPRS(base)     SAVE_GPR(13, base); SAVE_8GPRS(14, base); SAVE_10GPRS(22, base)
++#define REST_NVGPRS(base)     REST_GPR(13, base); REST_8GPRS(14, base); REST_10GPRS(22, base)
+ #endif
+ #define SAVE_2GPRS(n, base)   SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+-- 
+2.35.1
+
diff --git a/queue-5.15/powerpc-flexible-gpr-range-save-restore-macros.patch b/queue-5.15/powerpc-flexible-gpr-range-save-restore-macros.patch
new file mode 100644 (file)
index 0000000..c6c3971
--- /dev/null
@@ -0,0 +1,635 @@
+From c4482f2dac96098ffdf6e188e01bdb0367cf0f5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Oct 2021 16:13:22 +1000
+Subject: powerpc: flexible GPR range save/restore macros
+
+From: Nicholas Piggin <npiggin@gmail.com>
+
+[ Upstream commit aebd1fb45c622e9a2b06fb70665d084d3a8d6c78 ]
+
+Introduce macros that operate on a (start, end) range of GPRs, which
+reduces lines of code and need to do mental arithmetic while reading the
+code.
+
+Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
+Reviewed-by: Segher Boessenkool <segher@kernel.crashing.org>
+Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/20211022061322.2671178-1-npiggin@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/boot/crt0.S                      | 31 +++++++------
+ arch/powerpc/crypto/md5-asm.S                 | 10 ++---
+ arch/powerpc/crypto/sha1-powerpc-asm.S        |  6 +--
+ arch/powerpc/include/asm/ppc_asm.h            | 43 ++++++++++++-------
+ arch/powerpc/kernel/entry_32.S                | 23 ++++------
+ arch/powerpc/kernel/exceptions-64e.S          | 14 ++----
+ arch/powerpc/kernel/exceptions-64s.S          |  6 +--
+ arch/powerpc/kernel/head_32.h                 |  3 +-
+ arch/powerpc/kernel/head_booke.h              |  3 +-
+ arch/powerpc/kernel/interrupt_64.S            | 34 ++++++---------
+ arch/powerpc/kernel/optprobes_head.S          |  4 +-
+ arch/powerpc/kernel/tm.S                      | 15 ++-----
+ .../powerpc/kernel/trace/ftrace_64_mprofile.S | 15 +++----
+ arch/powerpc/kvm/book3s_hv_rmhandlers.S       |  5 +--
+ .../lib/test_emulate_step_exec_instr.S        |  8 ++--
+ 15 files changed, 94 insertions(+), 126 deletions(-)
+
+diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
+index 1d83966f5ef6..e8f10a599659 100644
+--- a/arch/powerpc/boot/crt0.S
++++ b/arch/powerpc/boot/crt0.S
+@@ -226,16 +226,19 @@ p_base:  mflr    r10             /* r10 now points to runtime addr of p_base */
+ #ifdef __powerpc64__
+ #define PROM_FRAME_SIZE 512
+-#define SAVE_GPR(n, base)       std     n,8*(n)(base)
+-#define REST_GPR(n, base)       ld      n,8*(n)(base)
+-#define SAVE_2GPRS(n, base)     SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+-#define SAVE_4GPRS(n, base)     SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+-#define SAVE_8GPRS(n, base)     SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+-#define SAVE_10GPRS(n, base)    SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+-#define REST_2GPRS(n, base)     REST_GPR(n, base); REST_GPR(n+1, base)
+-#define REST_4GPRS(n, base)     REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+-#define REST_8GPRS(n, base)     REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+-#define REST_10GPRS(n, base)    REST_8GPRS(n, base); REST_2GPRS(n+8, base)
++
++.macro OP_REGS op, width, start, end, base, offset
++      .Lreg=\start
++      .rept (\end - \start + 1)
++      \op     .Lreg,\offset+\width*.Lreg(\base)
++      .Lreg=.Lreg+1
++      .endr
++.endm
++
++#define SAVE_GPRS(start, end, base)   OP_REGS std, 8, start, end, base, 0
++#define REST_GPRS(start, end, base)   OP_REGS ld, 8, start, end, base, 0
++#define SAVE_GPR(n, base)             SAVE_GPRS(n, n, base)
++#define REST_GPR(n, base)             REST_GPRS(n, n, base)
+ /* prom handles the jump into and return from firmware.  The prom args pointer
+    is loaded in r3. */
+@@ -246,9 +249,7 @@ prom:
+       stdu    r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
+       SAVE_GPR(2, r1)
+-      SAVE_GPR(13, r1)
+-      SAVE_8GPRS(14, r1)
+-      SAVE_10GPRS(22, r1)
++      SAVE_GPRS(13, 31, r1)
+       mfcr    r10
+       std     r10,8*32(r1)
+       mfmsr   r10
+@@ -283,9 +284,7 @@ prom:
+       /* Restore other registers */
+       REST_GPR(2, r1)
+-      REST_GPR(13, r1)
+-      REST_8GPRS(14, r1)
+-      REST_10GPRS(22, r1)
++      REST_GPRS(13, 31, r1)
+       ld      r10,8*32(r1)
+       mtcr    r10
+diff --git a/arch/powerpc/crypto/md5-asm.S b/arch/powerpc/crypto/md5-asm.S
+index 948d100a2934..fa6bc440cf4a 100644
+--- a/arch/powerpc/crypto/md5-asm.S
++++ b/arch/powerpc/crypto/md5-asm.S
+@@ -38,15 +38,11 @@
+ #define INITIALIZE \
+       PPC_STLU r1,-INT_FRAME_SIZE(r1); \
+-      SAVE_8GPRS(14, r1);             /* push registers onto stack    */ \
+-      SAVE_4GPRS(22, r1);                                                \
+-      SAVE_GPR(26, r1)
++      SAVE_GPRS(14, 26, r1)           /* push registers onto stack    */
+ #define FINALIZE \
+-      REST_8GPRS(14, r1);             /* pop registers from stack     */ \
+-      REST_4GPRS(22, r1);                                                \
+-      REST_GPR(26, r1);                                                  \
+-      addi    r1,r1,INT_FRAME_SIZE;
++      REST_GPRS(14, 26, r1);          /* pop registers from stack     */ \
++      addi    r1,r1,INT_FRAME_SIZE
+ #ifdef __BIG_ENDIAN__
+ #define LOAD_DATA(reg, off) \
+diff --git a/arch/powerpc/crypto/sha1-powerpc-asm.S b/arch/powerpc/crypto/sha1-powerpc-asm.S
+index 23e248beff71..f0d5ed557ab1 100644
+--- a/arch/powerpc/crypto/sha1-powerpc-asm.S
++++ b/arch/powerpc/crypto/sha1-powerpc-asm.S
+@@ -125,8 +125,7 @@
+ _GLOBAL(powerpc_sha_transform)
+       PPC_STLU r1,-INT_FRAME_SIZE(r1)
+-      SAVE_8GPRS(14, r1)
+-      SAVE_10GPRS(22, r1)
++      SAVE_GPRS(14, 31, r1)
+       /* Load up A - E */
+       lwz     RA(0),0(r3)     /* A */
+@@ -184,7 +183,6 @@ _GLOBAL(powerpc_sha_transform)
+       stw     RD(0),12(r3)
+       stw     RE(0),16(r3)
+-      REST_8GPRS(14, r1)
+-      REST_10GPRS(22, r1)
++      REST_GPRS(14, 31, r1)
+       addi    r1,r1,INT_FRAME_SIZE
+       blr
+diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
+index 7be24048b8d1..f21e6bde17a1 100644
+--- a/arch/powerpc/include/asm/ppc_asm.h
++++ b/arch/powerpc/include/asm/ppc_asm.h
+@@ -16,30 +16,41 @@
+ #define SZL                   (BITS_PER_LONG/8)
++/*
++ * This expands to a sequence of operations with reg incrementing from
++ * start to end inclusive, of this form:
++ *
++ *   op  reg, (offset + (width * reg))(base)
++ *
++ * Note that offset is not the offset of the first operation unless start
++ * is zero (or width is zero).
++ */
++.macro OP_REGS op, width, start, end, base, offset
++      .Lreg=\start
++      .rept (\end - \start + 1)
++      \op     .Lreg, \offset + \width * .Lreg(\base)
++      .Lreg=.Lreg+1
++      .endr
++.endm
++
+ /*
+  * Macros for storing registers into and loading registers from
+  * exception frames.
+  */
+ #ifdef __powerpc64__
+-#define SAVE_GPR(n, base)     std     n,GPR0+8*(n)(base)
+-#define REST_GPR(n, base)     ld      n,GPR0+8*(n)(base)
+-#define SAVE_NVGPRS(base)     SAVE_8GPRS(14, base); SAVE_10GPRS(22, base)
+-#define REST_NVGPRS(base)     REST_8GPRS(14, base); REST_10GPRS(22, base)
++#define SAVE_GPRS(start, end, base)   OP_REGS std, 8, start, end, base, GPR0
++#define REST_GPRS(start, end, base)   OP_REGS ld, 8, start, end, base, GPR0
++#define SAVE_NVGPRS(base)             SAVE_GPRS(14, 31, base)
++#define REST_NVGPRS(base)             REST_GPRS(14, 31, base)
+ #else
+-#define SAVE_GPR(n, base)     stw     n,GPR0+4*(n)(base)
+-#define REST_GPR(n, base)     lwz     n,GPR0+4*(n)(base)
+-#define SAVE_NVGPRS(base)     SAVE_GPR(13, base); SAVE_8GPRS(14, base); SAVE_10GPRS(22, base)
+-#define REST_NVGPRS(base)     REST_GPR(13, base); REST_8GPRS(14, base); REST_10GPRS(22, base)
++#define SAVE_GPRS(start, end, base)   OP_REGS stw, 4, start, end, base, GPR0
++#define REST_GPRS(start, end, base)   OP_REGS lwz, 4, start, end, base, GPR0
++#define SAVE_NVGPRS(base)             SAVE_GPRS(13, 31, base)
++#define REST_NVGPRS(base)             REST_GPRS(13, 31, base)
+ #endif
+-#define SAVE_2GPRS(n, base)   SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+-#define SAVE_4GPRS(n, base)   SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+-#define SAVE_8GPRS(n, base)   SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+-#define SAVE_10GPRS(n, base)  SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+-#define REST_2GPRS(n, base)   REST_GPR(n, base); REST_GPR(n+1, base)
+-#define REST_4GPRS(n, base)   REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+-#define REST_8GPRS(n, base)   REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+-#define REST_10GPRS(n, base)  REST_8GPRS(n, base); REST_2GPRS(n+8, base)
++#define SAVE_GPR(n, base)             SAVE_GPRS(n, n, base)
++#define REST_GPR(n, base)             REST_GPRS(n, n, base)
+ #define SAVE_FPR(n, base)     stfd    n,8*TS_FPRWIDTH*(n)(base)
+ #define SAVE_2FPRS(n, base)   SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
+index 61fdd53cdd9a..c62dd9815965 100644
+--- a/arch/powerpc/kernel/entry_32.S
++++ b/arch/powerpc/kernel/entry_32.S
+@@ -90,8 +90,7 @@ transfer_to_syscall:
+       stw     r12,8(r1)
+       stw     r2,_TRAP(r1)
+       SAVE_GPR(0, r1)
+-      SAVE_4GPRS(3, r1)
+-      SAVE_2GPRS(7, r1)
++      SAVE_GPRS(3, 8, r1)
+       addi    r2,r10,-THREAD
+       SAVE_NVGPRS(r1)
+@@ -139,7 +138,7 @@ syscall_exit_finish:
+       mtxer   r5
+       lwz     r0,GPR0(r1)
+       lwz     r3,GPR3(r1)
+-      REST_8GPRS(4,r1)
++      REST_GPRS(4, 11, r1)
+       lwz     r12,GPR12(r1)
+       b       1b
+@@ -232,9 +231,9 @@ fast_exception_return:
+       beq     3f                      /* if not, we've got problems */
+ #endif
+-2:    REST_4GPRS(3, r11)
++2:    REST_GPRS(3, 6, r11)
+       lwz     r10,_CCR(r11)
+-      REST_2GPRS(1, r11)
++      REST_GPRS(1, 2, r11)
+       mtcr    r10
+       lwz     r10,_LINK(r11)
+       mtlr    r10
+@@ -298,16 +297,14 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+        * the reliable stack unwinder later on. Clear it.
+        */
+       stw     r0,8(r1)
+-      REST_4GPRS(7, r1)
+-      REST_2GPRS(11, r1)
++      REST_GPRS(7, 12, r1)
+       mtcr    r3
+       mtlr    r4
+       mtctr   r5
+       mtspr   SPRN_XER,r6
+-      REST_4GPRS(2, r1)
+-      REST_GPR(6, r1)
++      REST_GPRS(2, 6, r1)
+       REST_GPR(0, r1)
+       REST_GPR(1, r1)
+       rfi
+@@ -341,8 +338,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+       lwz     r6,_CCR(r1)
+       li      r0,0
+-      REST_4GPRS(7, r1)
+-      REST_2GPRS(11, r1)
++      REST_GPRS(7, 12, r1)
+       mtlr    r3
+       mtctr   r4
+@@ -354,7 +350,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+        */
+       stw     r0,8(r1)
+-      REST_4GPRS(2, r1)
++      REST_GPRS(2, 5, r1)
+       bne-    cr1,1f /* emulate stack store */
+       mtcr    r6
+@@ -430,8 +426,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return)
+       bne     interrupt_return;                                       \
+       lwz     r0,GPR0(r1);                                            \
+       lwz     r2,GPR2(r1);                                            \
+-      REST_4GPRS(3, r1);                                              \
+-      REST_2GPRS(7, r1);                                              \
++      REST_GPRS(3, 8, r1);                                            \
+       lwz     r10,_XER(r1);                                           \
+       lwz     r11,_CTR(r1);                                           \
+       mtspr   SPRN_XER,r10;                                           \
+diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
+index 711c66b76df1..67dc4e3179a0 100644
+--- a/arch/powerpc/kernel/exceptions-64e.S
++++ b/arch/powerpc/kernel/exceptions-64e.S
+@@ -198,8 +198,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
+       stdcx.  r0,0,r1         /* to clear the reservation */
+-      REST_4GPRS(2, r1)
+-      REST_4GPRS(6, r1)
++      REST_GPRS(2, 9, r1)
+       ld      r10,_CTR(r1)
+       ld      r11,_XER(r1)
+@@ -375,9 +374,7 @@ ret_from_mc_except:
+ exc_##n##_common:                                                         \
+       std     r0,GPR0(r1);            /* save r0 in stackframe */         \
+       std     r2,GPR2(r1);            /* save r2 in stackframe */         \
+-      SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe */    \
+-      SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe */     \
+-      std     r9,GPR9(r1);            /* save r9 in stackframe */         \
++      SAVE_GPRS(3, 9, r1);            /* save r3 - r9 in stackframe */    \
+       std     r10,_NIP(r1);           /* save SRR0 to stackframe */       \
+       std     r11,_MSR(r1);           /* save SRR1 to stackframe */       \
+       beq     2f;                     /* if from kernel mode */           \
+@@ -1061,9 +1058,7 @@ bad_stack_book3e:
+       std     r11,_ESR(r1)
+       std     r0,GPR0(r1);            /* save r0 in stackframe */         \
+       std     r2,GPR2(r1);            /* save r2 in stackframe */         \
+-      SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe */    \
+-      SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe */     \
+-      std     r9,GPR9(r1);            /* save r9 in stackframe */         \
++      SAVE_GPRS(3, 9, r1);            /* save r3 - r9 in stackframe */    \
+       ld      r3,PACA_EXGEN+EX_R10(r13);/* get back r10 */                \
+       ld      r4,PACA_EXGEN+EX_R11(r13);/* get back r11 */                \
+       mfspr   r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 XXX can be wrong */ \
+@@ -1077,8 +1072,7 @@ bad_stack_book3e:
+       std     r10,_LINK(r1)
+       std     r11,_CTR(r1)
+       std     r12,_XER(r1)
+-      SAVE_10GPRS(14,r1)
+-      SAVE_8GPRS(24,r1)
++      SAVE_GPRS(14, 31, r1)
+       lhz     r12,PACA_TRAP_SAVE(r13)
+       std     r12,_TRAP(r1)
+       addi    r11,r1,INT_FRAME_SIZE
+diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
+index eaf1f72131a1..277eccf0f086 100644
+--- a/arch/powerpc/kernel/exceptions-64s.S
++++ b/arch/powerpc/kernel/exceptions-64s.S
+@@ -574,8 +574,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+       ld      r10,IAREA+EX_CTR(r13)
+       std     r10,_CTR(r1)
+       std     r2,GPR2(r1)             /* save r2 in stackframe        */
+-      SAVE_4GPRS(3, r1)               /* save r3 - r6 in stackframe   */
+-      SAVE_2GPRS(7, r1)               /* save r7, r8 in stackframe    */
++      SAVE_GPRS(3, 8, r1)             /* save r3 - r8 in stackframe   */
+       mflr    r9                      /* Get LR, later save to stack  */
+       ld      r2,PACATOC(r13)         /* get kernel TOC into r2       */
+       std     r9,_LINK(r1)
+@@ -693,8 +692,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+       mtlr    r9
+       ld      r9,_CCR(r1)
+       mtcr    r9
+-      REST_8GPRS(2, r1)
+-      REST_4GPRS(10, r1)
++      REST_GPRS(2, 13, r1)
+       REST_GPR(0, r1)
+       /* restore original r1. */
+       ld      r1,GPR1(r1)
+diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h
+index 349c4a820231..261c79bdbe53 100644
+--- a/arch/powerpc/kernel/head_32.h
++++ b/arch/powerpc/kernel/head_32.h
+@@ -115,8 +115,7 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
+       stw     r10,8(r1)
+       li      r10, \trapno
+       stw     r10,_TRAP(r1)
+-      SAVE_4GPRS(3, r1)
+-      SAVE_2GPRS(7, r1)
++      SAVE_GPRS(3, 8, r1)
+       SAVE_NVGPRS(r1)
+       stw     r2,GPR2(r1)
+       stw     r12,_NIP(r1)
+diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
+index ef8d1b1c234e..bb6d5d0fc4ac 100644
+--- a/arch/powerpc/kernel/head_booke.h
++++ b/arch/powerpc/kernel/head_booke.h
+@@ -87,8 +87,7 @@ END_BTB_FLUSH_SECTION
+       stw     r10, 8(r1)
+       li      r10, \trapno
+       stw     r10,_TRAP(r1)
+-      SAVE_4GPRS(3, r1)
+-      SAVE_2GPRS(7, r1)
++      SAVE_GPRS(3, 8, r1)
+       SAVE_NVGPRS(r1)
+       stw     r2,GPR2(r1)
+       stw     r12,_NIP(r1)
+diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S
+index 4c6d1a8dcefe..ff8c8c03f41a 100644
+--- a/arch/powerpc/kernel/interrupt_64.S
++++ b/arch/powerpc/kernel/interrupt_64.S
+@@ -166,10 +166,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+        * The value of AMR only matters while we're in the kernel.
+        */
+       mtcr    r2
+-      ld      r2,GPR2(r1)
+-      ld      r3,GPR3(r1)
+-      ld      r13,GPR13(r1)
+-      ld      r1,GPR1(r1)
++      REST_GPRS(2, 3, r1)
++      REST_GPR(13, r1)
++      REST_GPR(1, r1)
+       RFSCV_TO_USER
+       b       .       /* prevent speculative execution */
+@@ -187,9 +186,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+       mtctr   r3
+       mtlr    r4
+       mtspr   SPRN_XER,r5
+-      REST_10GPRS(2, r1)
+-      REST_2GPRS(12, r1)
+-      ld      r1,GPR1(r1)
++      REST_GPRS(2, 13, r1)
++      REST_GPR(1, r1)
+       RFI_TO_USER
+ .Lsyscall_vectored_\name\()_rst_end:
+@@ -378,10 +376,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+        * The value of AMR only matters while we're in the kernel.
+        */
+       mtcr    r2
+-      ld      r2,GPR2(r1)
+-      ld      r3,GPR3(r1)
+-      ld      r13,GPR13(r1)
+-      ld      r1,GPR1(r1)
++      REST_GPRS(2, 3, r1)
++      REST_GPR(13, r1)
++      REST_GPR(1, r1)
+       RFI_TO_USER
+       b       .       /* prevent speculative execution */
+@@ -392,8 +389,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+       mtctr   r3
+       mtspr   SPRN_XER,r4
+       ld      r0,GPR0(r1)
+-      REST_8GPRS(4, r1)
+-      ld      r12,GPR12(r1)
++      REST_GPRS(4, 12, r1)
+       b       .Lsyscall_restore_regs_cont
+ .Lsyscall_rst_end:
+@@ -522,17 +518,14 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+       ld      r6,_XER(r1)
+       li      r0,0
+-      REST_4GPRS(7, r1)
+-      REST_2GPRS(11, r1)
+-      REST_GPR(13, r1)
++      REST_GPRS(7, 13, r1)
+       mtcr    r3
+       mtlr    r4
+       mtctr   r5
+       mtspr   SPRN_XER,r6
+-      REST_4GPRS(2, r1)
+-      REST_GPR(6, r1)
++      REST_GPRS(2, 6, r1)
+       REST_GPR(0, r1)
+       REST_GPR(1, r1)
+       .ifc \srr,srr
+@@ -629,8 +622,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+       ld      r6,_CCR(r1)
+       li      r0,0
+-      REST_4GPRS(7, r1)
+-      REST_2GPRS(11, r1)
++      REST_GPRS(7, 12, r1)
+       mtlr    r3
+       mtctr   r4
+@@ -642,7 +634,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+        */
+       std     r0,STACK_FRAME_OVERHEAD-16(r1)
+-      REST_4GPRS(2, r1)
++      REST_GPRS(2, 5, r1)
+       bne-    cr1,1f /* emulate stack store */
+       mtcr    r6
+diff --git a/arch/powerpc/kernel/optprobes_head.S b/arch/powerpc/kernel/optprobes_head.S
+index 19ea3312403c..5c7f0b4b784b 100644
+--- a/arch/powerpc/kernel/optprobes_head.S
++++ b/arch/powerpc/kernel/optprobes_head.S
+@@ -10,8 +10,8 @@
+ #include <asm/asm-offsets.h>
+ #ifdef CONFIG_PPC64
+-#define SAVE_30GPRS(base) SAVE_10GPRS(2,base); SAVE_10GPRS(12,base); SAVE_10GPRS(22,base)
+-#define REST_30GPRS(base) REST_10GPRS(2,base); REST_10GPRS(12,base); REST_10GPRS(22,base)
++#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base)
++#define REST_30GPRS(base) REST_GPRS(2, 31, base)
+ #define TEMPLATE_FOR_IMM_LOAD_INSNS   nop; nop; nop; nop; nop
+ #else
+ #define SAVE_30GPRS(base) stmw        r2, GPR2(base)
+diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
+index 2b91f233b05d..3beecc32940b 100644
+--- a/arch/powerpc/kernel/tm.S
++++ b/arch/powerpc/kernel/tm.S
+@@ -226,11 +226,8 @@ _GLOBAL(tm_reclaim)
+       /* Sync the userland GPRs 2-12, 14-31 to thread->regs: */
+       SAVE_GPR(0, r7)                         /* user r0 */
+-      SAVE_GPR(2, r7)                         /* user r2 */
+-      SAVE_4GPRS(3, r7)                       /* user r3-r6 */
+-      SAVE_GPR(8, r7)                         /* user r8 */
+-      SAVE_GPR(9, r7)                         /* user r9 */
+-      SAVE_GPR(10, r7)                        /* user r10 */
++      SAVE_GPRS(2, 6, r7)                     /* user r2-r6 */
++      SAVE_GPRS(8, 10, r7)                    /* user r8-r10 */
+       ld      r3, GPR1(r1)                    /* user r1 */
+       ld      r4, GPR7(r1)                    /* user r7 */
+       ld      r5, GPR11(r1)                   /* user r11 */
+@@ -445,12 +442,8 @@ restore_gprs:
+       ld      r6, THREAD_TM_PPR(r3)
+       REST_GPR(0, r7)                         /* GPR0 */
+-      REST_2GPRS(2, r7)                       /* GPR2-3 */
+-      REST_GPR(4, r7)                         /* GPR4 */
+-      REST_4GPRS(8, r7)                       /* GPR8-11 */
+-      REST_2GPRS(12, r7)                      /* GPR12-13 */
+-
+-      REST_NVGPRS(r7)                         /* GPR14-31 */
++      REST_GPRS(2, 4, r7)                     /* GPR2-4 */
++      REST_GPRS(8, 31, r7)                    /* GPR8-31 */
+       /* Load up PPR and DSCR here so we don't run with user values for long */
+       mtspr   SPRN_DSCR, r5
+diff --git a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
+index f9fd5f743eba..d636fc755f60 100644
+--- a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
++++ b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
+@@ -41,15 +41,14 @@ _GLOBAL(ftrace_regs_caller)
+       /* Save all gprs to pt_regs */
+       SAVE_GPR(0, r1)
+-      SAVE_10GPRS(2, r1)
++      SAVE_GPRS(2, 11, r1)
+       /* Ok to continue? */
+       lbz     r3, PACA_FTRACE_ENABLED(r13)
+       cmpdi   r3, 0
+       beq     ftrace_no_trace
+-      SAVE_10GPRS(12, r1)
+-      SAVE_10GPRS(22, r1)
++      SAVE_GPRS(12, 31, r1)
+       /* Save previous stack pointer (r1) */
+       addi    r8, r1, SWITCH_FRAME_SIZE
+@@ -108,10 +107,8 @@ ftrace_regs_call:
+ #endif
+       /* Restore gprs */
+-      REST_GPR(0,r1)
+-      REST_10GPRS(2,r1)
+-      REST_10GPRS(12,r1)
+-      REST_10GPRS(22,r1)
++      REST_GPR(0, r1)
++      REST_GPRS(2, 31, r1)
+       /* Restore possibly modified LR */
+       ld      r0, _LINK(r1)
+@@ -157,7 +154,7 @@ _GLOBAL(ftrace_caller)
+       stdu    r1, -SWITCH_FRAME_SIZE(r1)
+       /* Save all gprs to pt_regs */
+-      SAVE_8GPRS(3, r1)
++      SAVE_GPRS(3, 10, r1)
+       lbz     r3, PACA_FTRACE_ENABLED(r13)
+       cmpdi   r3, 0
+@@ -194,7 +191,7 @@ ftrace_call:
+       mtctr   r3
+       /* Restore gprs */
+-      REST_8GPRS(3,r1)
++      REST_GPRS(3, 10, r1)
+       /* Restore callee's TOC */
+       ld      r2, 24(r1)
+diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+index 32a4b4d412b9..81fc1e0ebe9a 100644
+--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
++++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+@@ -2711,8 +2711,7 @@ kvmppc_bad_host_intr:
+       std     r0, GPR0(r1)
+       std     r9, GPR1(r1)
+       std     r2, GPR2(r1)
+-      SAVE_4GPRS(3, r1)
+-      SAVE_2GPRS(7, r1)
++      SAVE_GPRS(3, 8, r1)
+       srdi    r0, r12, 32
+       clrldi  r12, r12, 32
+       std     r0, _CCR(r1)
+@@ -2735,7 +2734,7 @@ kvmppc_bad_host_intr:
+       ld      r9, HSTATE_SCRATCH2(r13)
+       ld      r12, HSTATE_SCRATCH0(r13)
+       GET_SCRATCH0(r0)
+-      SAVE_4GPRS(9, r1)
++      SAVE_GPRS(9, 12, r1)
+       std     r0, GPR13(r1)
+       SAVE_NVGPRS(r1)
+       ld      r5, HSTATE_CFAR(r13)
+diff --git a/arch/powerpc/lib/test_emulate_step_exec_instr.S b/arch/powerpc/lib/test_emulate_step_exec_instr.S
+index 9ef941d958d8..5473f9d03df3 100644
+--- a/arch/powerpc/lib/test_emulate_step_exec_instr.S
++++ b/arch/powerpc/lib/test_emulate_step_exec_instr.S
+@@ -37,7 +37,7 @@ _GLOBAL(exec_instr)
+        * The stack pointer (GPR1) and the thread pointer (GPR13) are not
+        * saved as these should not be modified anyway.
+        */
+-      SAVE_2GPRS(2, r1)
++      SAVE_GPRS(2, 3, r1)
+       SAVE_NVGPRS(r1)
+       /*
+@@ -75,8 +75,7 @@ _GLOBAL(exec_instr)
+       /* Load GPRs from pt_regs */
+       REST_GPR(0, r31)
+-      REST_10GPRS(2, r31)
+-      REST_GPR(12, r31)
++      REST_GPRS(2, 12, r31)
+       REST_NVGPRS(r31)
+       /* Placeholder for the test instruction */
+@@ -99,8 +98,7 @@ _GLOBAL(exec_instr)
+       subi    r3, r3, GPR0
+       SAVE_GPR(0, r3)
+       SAVE_GPR(2, r3)
+-      SAVE_8GPRS(4, r3)
+-      SAVE_GPR(12, r3)
++      SAVE_GPRS(4, 12, r3)
+       SAVE_NVGPRS(r3)
+       /* Save resulting LR to pt_regs */
+-- 
+2.35.1
+
diff --git a/queue-5.15/powerpc-tm-fix-more-userspace-r13-corruption.patch b/queue-5.15/powerpc-tm-fix-more-userspace-r13-corruption.patch
new file mode 100644 (file)
index 0000000..c9f662a
--- /dev/null
@@ -0,0 +1,119 @@
+From 021729411f0b4d327fe284fcbbe0af306d60a47b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Mar 2022 12:47:33 +1000
+Subject: powerpc/tm: Fix more userspace r13 corruption
+
+From: Nicholas Piggin <npiggin@gmail.com>
+
+[ Upstream commit 9d71165d3934e607070c4e48458c0cf161b1baea ]
+
+Commit cf13435b730a ("powerpc/tm: Fix userspace r13 corruption") fixes a
+problem in treclaim where a SLB miss can occur on the
+thread_struct->ckpt_regs while SCRATCH0 is live with the saved user r13
+value, clobbering it with the kernel r13 and ultimately resulting in
+kernel r13 being stored in ckpt_regs.
+
+There is an equivalent problem in trechkpt where the user r13 value is
+loaded into r13 from chkpt_regs to be recheckpointed, but a SLB miss
+could occur on ckpt_regs accesses after that, which will result in r13
+being clobbered with a kernel value and that will get recheckpointed and
+then restored to user registers.
+
+The same memory page is accessed right before this critical window where
+a SLB miss could cause corruption, so hitting the bug requires the SLB
+entry be removed within a small window of instructions, which is
+possible if a SLB related MCE hits there. PAPR also permits the
+hypervisor to discard this SLB entry (because slb_shadow->persistent is
+only set to SLB_NUM_BOLTED) although it's not known whether any
+implementations would do this (KVM does not). So this is an extremely
+unlikely bug, only found by inspection.
+
+Fix this by also storing user r13 in a temporary location on the kernel
+stack and don't change the r13 register from kernel r13 until the RI=0
+critical section that does not fault.
+
+The SCRATCH0 change is not strictly part of the fix, it's only used in
+the RI=0 section so it does not have the same problem as the previous
+SCRATCH0 bug.
+
+Fixes: 98ae22e15b43 ("powerpc: Add helper functions for transactional memory context switching")
+Cc: stable@vger.kernel.org # v3.9+
+Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
+Acked-by: Michael Neuling <mikey@neuling.org>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/20220311024733.48926-1-npiggin@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/kernel/tm.S | 25 ++++++++++++++++---------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
+index 3beecc32940b..5a0f023a26e9 100644
+--- a/arch/powerpc/kernel/tm.S
++++ b/arch/powerpc/kernel/tm.S
+@@ -443,7 +443,8 @@ restore_gprs:
+       REST_GPR(0, r7)                         /* GPR0 */
+       REST_GPRS(2, 4, r7)                     /* GPR2-4 */
+-      REST_GPRS(8, 31, r7)                    /* GPR8-31 */
++      REST_GPRS(8, 12, r7)                    /* GPR8-12 */
++      REST_GPRS(14, 31, r7)                   /* GPR14-31 */
+       /* Load up PPR and DSCR here so we don't run with user values for long */
+       mtspr   SPRN_DSCR, r5
+@@ -479,18 +480,24 @@ restore_gprs:
+       REST_GPR(6, r7)
+       /*
+-       * Store r1 and r5 on the stack so that we can access them after we
+-       * clear MSR RI.
++       * Store user r1 and r5 and r13 on the stack (in the unused save
++       * areas / compiler reserved areas), so that we can access them after
++       * we clear MSR RI.
+        */
+       REST_GPR(5, r7)
+       std     r5, -8(r1)
+-      ld      r5, GPR1(r7)
++      ld      r5, GPR13(r7)
+       std     r5, -16(r1)
++      ld      r5, GPR1(r7)
++      std     r5, -24(r1)
+       REST_GPR(7, r7)
+-      /* Clear MSR RI since we are about to use SCRATCH0. EE is already off */
++      /* Stash the stack pointer away for use after recheckpoint */
++      std     r1, PACAR1(r13)
++
++      /* Clear MSR RI since we are about to clobber r13. EE is already off */
+       li      r5, 0
+       mtmsrd  r5, 1
+@@ -501,9 +508,9 @@ restore_gprs:
+        * until we turn MSR RI back on.
+        */
+-      SET_SCRATCH0(r1)
+       ld      r5, -8(r1)
+-      ld      r1, -16(r1)
++      ld      r13, -16(r1)
++      ld      r1, -24(r1)
+       /* Commit register state as checkpointed state: */
+       TRECHKPT
+@@ -519,9 +526,9 @@ restore_gprs:
+        */
+       GET_PACA(r13)
+-      GET_SCRATCH0(r1)
++      ld      r1, PACAR1(r13)
+-      /* R1 is restored, so we are recoverable again.  EE is still off */
++      /* R13, R1 is restored, so we are recoverable again.  EE is still off */
+       li      r4, MSR_RI
+       mtmsrd  r4, 1
+-- 
+2.35.1
+
diff --git a/queue-5.15/powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch b/queue-5.15/powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch
new file mode 100644 (file)
index 0000000..c6dadda
--- /dev/null
@@ -0,0 +1,142 @@
+From ee2f47969656f7ab507c4c3f776f28ea6067bb58 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 May 2022 22:50:10 +1000
+Subject: powerpc/vdso: Fix incorrect CFI in gettimeofday.S
+
+From: Michael Ellerman <mpe@ellerman.id.au>
+
+[ Upstream commit 6d65028eb67dbb7627651adfc460d64196d38bd8 ]
+
+As reported by Alan, the CFI (Call Frame Information) in the VDSO time
+routines is incorrect since commit ce7d8056e38b ("powerpc/vdso: Prepare
+for switching VDSO to generic C implementation.").
+
+DWARF has a concept called the CFA (Canonical Frame Address), which on
+powerpc is calculated as an offset from the stack pointer (r1). That
+means when the stack pointer is changed there must be a corresponding
+CFI directive to update the calculation of the CFA.
+
+The current code is missing those directives for the changes to r1,
+which prevents gdb from being able to generate a backtrace from inside
+VDSO functions, eg:
+
+  Breakpoint 1, 0x00007ffff7f804dc in __kernel_clock_gettime ()
+  (gdb) bt
+  #0  0x00007ffff7f804dc in __kernel_clock_gettime ()
+  #1  0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
+  #2  0x00007fffffffd960 in ?? ()
+  #3  0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
+  Backtrace stopped: frame did not save the PC
+
+Alan helpfully describes some rules for correctly maintaining the CFI information:
+
+  1) Every adjustment to the current frame address reg (ie. r1) must be
+     described, and exactly at the instruction where r1 changes. Why?
+     Because stack unwinding might want to access previous frames.
+
+  2) If a function changes LR or any non-volatile register, the save
+     location for those regs must be given. The CFI can be at any
+     instruction after the saves up to the point that the reg is
+     changed.
+     (Exception: LR save should be described before a bl. not after)
+
+  3) If asychronous unwind info is needed then restores of LR and
+     non-volatile regs must also be described. The CFI can be at any
+     instruction after the reg is restored up to the point where the
+     save location is (potentially) trashed.
+
+Fix the inability to backtrace by adding CFI directives describing the
+changes to r1, ie. satisfying rule 1.
+
+Also change the information for LR to point to the copy saved on the
+stack, not the value in r0 that will be overwritten by the function
+call.
+
+Finally, add CFI directives describing the save/restore of r2.
+
+With the fix gdb can correctly back trace and navigate up and down the stack:
+
+  Breakpoint 1, 0x00007ffff7f804dc in __kernel_clock_gettime ()
+  (gdb) bt
+  #0  0x00007ffff7f804dc in __kernel_clock_gettime ()
+  #1  0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
+  #2  0x0000000100015b60 in gettime ()
+  #3  0x000000010000c8bc in print_long_format ()
+  #4  0x000000010000d180 in print_current_files ()
+  #5  0x00000001000054ac in main ()
+  (gdb) up
+  #1  0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
+  (gdb)
+  #2  0x0000000100015b60 in gettime ()
+  (gdb)
+  #3  0x000000010000c8bc in print_long_format ()
+  (gdb)
+  #4  0x000000010000d180 in print_current_files ()
+  (gdb)
+  #5  0x00000001000054ac in main ()
+  (gdb)
+  Initial frame selected; you cannot go up.
+  (gdb) down
+  #4  0x000000010000d180 in print_current_files ()
+  (gdb)
+  #3  0x000000010000c8bc in print_long_format ()
+  (gdb)
+  #2  0x0000000100015b60 in gettime ()
+  (gdb)
+  #1  0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
+  (gdb)
+  #0  0x00007ffff7f804dc in __kernel_clock_gettime ()
+  (gdb)
+
+Fixes: ce7d8056e38b ("powerpc/vdso: Prepare for switching VDSO to generic C implementation.")
+Cc: stable@vger.kernel.org # v5.11+
+Reported-by: Alan Modra <amodra@gmail.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Reviewed-by: Segher Boessenkool <segher@kernel.crashing.org>
+Link: https://lore.kernel.org/r/20220502125010.1319370-1-mpe@ellerman.id.au
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/kernel/vdso32/gettimeofday.S | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
+index dd2099128b8f..42d40f895c1f 100644
+--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
+@@ -22,12 +22,15 @@
+ .macro cvdso_call funct call_time=0
+   .cfi_startproc
+       PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
++  .cfi_adjust_cfa_offset PPC_MIN_STKFRM
+       mflr            r0
+-  .cfi_register lr, r0
+       PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
++  .cfi_adjust_cfa_offset PPC_MIN_STKFRM
+       PPC_STL         r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
++  .cfi_rel_offset lr, PPC_MIN_STKFRM + PPC_LR_STKOFF
+ #ifdef __powerpc64__
+       PPC_STL         r2, PPC_MIN_STKFRM + STK_GOT(r1)
++  .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT
+ #endif
+       get_datapage    r5
+       .ifeq   \call_time
+@@ -39,13 +42,15 @@
+       PPC_LL          r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+ #ifdef __powerpc64__
+       PPC_LL          r2, PPC_MIN_STKFRM + STK_GOT(r1)
++  .cfi_restore r2
+ #endif
+       .ifeq   \call_time
+       cmpwi           r3, 0
+       .endif
+       mtlr            r0
+-  .cfi_restore lr
+       addi            r1, r1, 2 * PPC_MIN_STKFRM
++  .cfi_restore lr
++  .cfi_def_cfa_offset 0
+       crclr           so
+       .ifeq   \call_time
+       beqlr+
+-- 
+2.35.1
+
diff --git a/queue-5.15/powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch b/queue-5.15/powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch
new file mode 100644 (file)
index 0000000..29e6074
--- /dev/null
@@ -0,0 +1,143 @@
+From 0b7cd13fa76cd848aad5f2f2298615e8b616e0ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Jan 2022 16:30:34 +0000
+Subject: powerpc/vdso: Move cvdso_call macro into gettimeofday.S
+
+From: Christophe Leroy <christophe.leroy@csgroup.eu>
+
+[ Upstream commit 692b21d78046851e75dc25bba773189c670b49c2 ]
+
+Now that gettimeofday.S is unique, move cvdso_call macro
+into that file which is the only user.
+
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/72720359d4c58e3a3b96dd74952741225faac3de.1642782130.git.christophe.leroy@csgroup.eu
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/vdso/gettimeofday.h | 52 +-------------------
+ arch/powerpc/kernel/vdso32/gettimeofday.S    | 44 ++++++++++++++++-
+ 2 files changed, 45 insertions(+), 51 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/vdso/gettimeofday.h b/arch/powerpc/include/asm/vdso/gettimeofday.h
+index df00e91c9a90..f0a4cf01e85c 100644
+--- a/arch/powerpc/include/asm/vdso/gettimeofday.h
++++ b/arch/powerpc/include/asm/vdso/gettimeofday.h
+@@ -2,57 +2,9 @@
+ #ifndef _ASM_POWERPC_VDSO_GETTIMEOFDAY_H
+ #define _ASM_POWERPC_VDSO_GETTIMEOFDAY_H
+-#include <asm/page.h>
+-
+-#ifdef __ASSEMBLY__
+-
+-#include <asm/ppc_asm.h>
+-
+-/*
+- * The macro sets two stack frames, one for the caller and one for the callee
+- * because there are no requirement for the caller to set a stack frame when
+- * calling VDSO so it may have omitted to set one, especially on PPC64
+- */
+-
+-.macro cvdso_call funct call_time=0
+-  .cfi_startproc
+-      PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
+-      mflr            r0
+-  .cfi_register lr, r0
+-      PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
+-      PPC_STL         r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+-#ifdef __powerpc64__
+-      PPC_STL         r2, PPC_MIN_STKFRM + STK_GOT(r1)
+-#endif
+-      get_datapage    r5
+-      .ifeq   \call_time
+-      addi            r5, r5, VDSO_DATA_OFFSET
+-      .else
+-      addi            r4, r5, VDSO_DATA_OFFSET
+-      .endif
+-      bl              DOTSYM(\funct)
+-      PPC_LL          r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+-#ifdef __powerpc64__
+-      PPC_LL          r2, PPC_MIN_STKFRM + STK_GOT(r1)
+-#endif
+-      .ifeq   \call_time
+-      cmpwi           r3, 0
+-      .endif
+-      mtlr            r0
+-  .cfi_restore lr
+-      addi            r1, r1, 2 * PPC_MIN_STKFRM
+-      crclr           so
+-      .ifeq   \call_time
+-      beqlr+
+-      crset           so
+-      neg             r3, r3
+-      .endif
+-      blr
+-  .cfi_endproc
+-.endm
+-
+-#else
++#ifndef __ASSEMBLY__
++#include <asm/page.h>
+ #include <asm/vdso/timebase.h>
+ #include <asm/barrier.h>
+ #include <asm/unistd.h>
+diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
+index 9b3ac09423c8..dd2099128b8f 100644
+--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
+@@ -12,7 +12,49 @@
+ #include <asm/vdso_datapage.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/unistd.h>
+-#include <asm/vdso/gettimeofday.h>
++
++/*
++ * The macro sets two stack frames, one for the caller and one for the callee
++ * because there are no requirement for the caller to set a stack frame when
++ * calling VDSO so it may have omitted to set one, especially on PPC64
++ */
++
++.macro cvdso_call funct call_time=0
++  .cfi_startproc
++      PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
++      mflr            r0
++  .cfi_register lr, r0
++      PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
++      PPC_STL         r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
++#ifdef __powerpc64__
++      PPC_STL         r2, PPC_MIN_STKFRM + STK_GOT(r1)
++#endif
++      get_datapage    r5
++      .ifeq   \call_time
++      addi            r5, r5, VDSO_DATA_OFFSET
++      .else
++      addi            r4, r5, VDSO_DATA_OFFSET
++      .endif
++      bl              DOTSYM(\funct)
++      PPC_LL          r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
++#ifdef __powerpc64__
++      PPC_LL          r2, PPC_MIN_STKFRM + STK_GOT(r1)
++#endif
++      .ifeq   \call_time
++      cmpwi           r3, 0
++      .endif
++      mtlr            r0
++  .cfi_restore lr
++      addi            r1, r1, 2 * PPC_MIN_STKFRM
++      crclr           so
++      .ifeq   \call_time
++      beqlr+
++      crset           so
++      neg             r3, r3
++      .endif
++      blr
++  .cfi_endproc
++.endm
+       .text
+ /*
+-- 
+2.35.1
+
diff --git a/queue-5.15/powerpc-vdso-remove-cvdso_call_time-macro.patch b/queue-5.15/powerpc-vdso-remove-cvdso_call_time-macro.patch
new file mode 100644 (file)
index 0000000..02739e1
--- /dev/null
@@ -0,0 +1,115 @@
+From cdba38a2a3d85a93e10553e853efff9cf09c10cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Jan 2022 16:30:30 +0000
+Subject: powerpc/vdso: Remove cvdso_call_time macro
+
+From: Christophe Leroy <christophe.leroy@csgroup.eu>
+
+[ Upstream commit 9b97bea90072a075363a200dd7b54ad4a24e9491 ]
+
+cvdso_call_time macro is very similar to cvdso_call macro.
+
+Add a call_time argument to cvdso_call which is 0 by default
+and set to 1 when using cvdso_call to call __c_kernel_time().
+
+Return returned value as is with CR[SO] cleared when it is used
+for time().
+
+Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/837a260ad86fc1ce297a562c2117fd69be5f7b5c.1642782130.git.christophe.leroy@csgroup.eu
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/vdso/gettimeofday.h | 37 ++++++--------------
+ arch/powerpc/kernel/vdso32/gettimeofday.S    |  2 +-
+ 2 files changed, 11 insertions(+), 28 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/vdso/gettimeofday.h b/arch/powerpc/include/asm/vdso/gettimeofday.h
+index 1faff0be1111..df00e91c9a90 100644
+--- a/arch/powerpc/include/asm/vdso/gettimeofday.h
++++ b/arch/powerpc/include/asm/vdso/gettimeofday.h
+@@ -9,12 +9,12 @@
+ #include <asm/ppc_asm.h>
+ /*
+- * The macros sets two stack frames, one for the caller and one for the callee
++ * The macro sets two stack frames, one for the caller and one for the callee
+  * because there are no requirement for the caller to set a stack frame when
+  * calling VDSO so it may have omitted to set one, especially on PPC64
+  */
+-.macro cvdso_call funct
++.macro cvdso_call funct call_time=0
+   .cfi_startproc
+       PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
+       mflr            r0
+@@ -25,45 +25,28 @@
+       PPC_STL         r2, PPC_MIN_STKFRM + STK_GOT(r1)
+ #endif
+       get_datapage    r5
++      .ifeq   \call_time
+       addi            r5, r5, VDSO_DATA_OFFSET
++      .else
++      addi            r4, r5, VDSO_DATA_OFFSET
++      .endif
+       bl              DOTSYM(\funct)
+       PPC_LL          r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+ #ifdef __powerpc64__
+       PPC_LL          r2, PPC_MIN_STKFRM + STK_GOT(r1)
+ #endif
++      .ifeq   \call_time
+       cmpwi           r3, 0
++      .endif
+       mtlr            r0
+   .cfi_restore lr
+       addi            r1, r1, 2 * PPC_MIN_STKFRM
+       crclr           so
++      .ifeq   \call_time
+       beqlr+
+       crset           so
+       neg             r3, r3
+-      blr
+-  .cfi_endproc
+-.endm
+-
+-.macro cvdso_call_time funct
+-  .cfi_startproc
+-      PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
+-      mflr            r0
+-  .cfi_register lr, r0
+-      PPC_STLU        r1, -PPC_MIN_STKFRM(r1)
+-      PPC_STL         r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+-#ifdef __powerpc64__
+-      PPC_STL         r2, PPC_MIN_STKFRM + STK_GOT(r1)
+-#endif
+-      get_datapage    r4
+-      addi            r4, r4, VDSO_DATA_OFFSET
+-      bl              DOTSYM(\funct)
+-      PPC_LL          r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+-#ifdef __powerpc64__
+-      PPC_LL          r2, PPC_MIN_STKFRM + STK_GOT(r1)
+-#endif
+-      crclr           so
+-      mtlr            r0
+-  .cfi_restore lr
+-      addi            r1, r1, 2 * PPC_MIN_STKFRM
++      .endif
+       blr
+   .cfi_endproc
+ .endm
+diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
+index d21d08140a5e..9b3ac09423c8 100644
+--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
+@@ -63,7 +63,7 @@ V_FUNCTION_END(__kernel_clock_getres)
+  *
+  */
+ V_FUNCTION_BEGIN(__kernel_time)
+-      cvdso_call_time __c_kernel_time
++      cvdso_call __c_kernel_time call_time=1
+ V_FUNCTION_END(__kernel_time)
+ /* Routines for restoring integer registers, called by the compiler.  */
+-- 
+2.35.1
+
diff --git a/queue-5.15/qed-improve-the-stack-space-of-filter_config.patch b/queue-5.15/qed-improve-the-stack-space-of-filter_config.patch
new file mode 100644 (file)
index 0000000..bbeb30b
--- /dev/null
@@ -0,0 +1,216 @@
+From 6f5729b934b920230b00008013eb4101eca246a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Sep 2021 10:50:24 +0300
+Subject: qed: Improve the stack space of filter_config()
+
+From: Shai Malin <smalin@marvell.com>
+
+[ Upstream commit f55e36d5ab76c3097ff36ecea60b91c6b0d80fc8 ]
+
+As it was reported and discussed in: https://lore.kernel.org/lkml/CAHk-=whF9F89vsfH8E9TGc0tZA-yhzi2Di8wOtquNB5vRkFX5w@mail.gmail.com/
+This patch improves the stack space of qede_config_rx_mode() by
+splitting filter_config() to 3 functions and removing the
+union qed_filter_type_params.
+
+Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
+Signed-off-by: Ariel Elior <aelior@marvell.com>
+Signed-off-by: Shai Malin <smalin@marvell.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/qlogic/qed/qed_l2.c      | 23 ++-------
+ .../net/ethernet/qlogic/qede/qede_filter.c    | 47 ++++++++-----------
+ include/linux/qed/qed_eth_if.h                | 21 ++++-----
+ 3 files changed, 30 insertions(+), 61 deletions(-)
+
+diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
+index dfaf10edfabf..ba8c7a31cce1 100644
+--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
+@@ -2763,25 +2763,6 @@ static int qed_configure_filter_mcast(struct qed_dev *cdev,
+       return qed_filter_mcast_cmd(cdev, &mcast, QED_SPQ_MODE_CB, NULL);
+ }
+-static int qed_configure_filter(struct qed_dev *cdev,
+-                              struct qed_filter_params *params)
+-{
+-      enum qed_filter_rx_mode_type accept_flags;
+-
+-      switch (params->type) {
+-      case QED_FILTER_TYPE_UCAST:
+-              return qed_configure_filter_ucast(cdev, &params->filter.ucast);
+-      case QED_FILTER_TYPE_MCAST:
+-              return qed_configure_filter_mcast(cdev, &params->filter.mcast);
+-      case QED_FILTER_TYPE_RX_MODE:
+-              accept_flags = params->filter.accept_flags;
+-              return qed_configure_filter_rx_mode(cdev, accept_flags);
+-      default:
+-              DP_NOTICE(cdev, "Unknown filter type %d\n", (int)params->type);
+-              return -EINVAL;
+-      }
+-}
+-
+ static int qed_configure_arfs_searcher(struct qed_dev *cdev,
+                                      enum qed_filter_config_mode mode)
+ {
+@@ -2904,7 +2885,9 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
+       .q_rx_stop = &qed_stop_rxq,
+       .q_tx_start = &qed_start_txq,
+       .q_tx_stop = &qed_stop_txq,
+-      .filter_config = &qed_configure_filter,
++      .filter_config_rx_mode = &qed_configure_filter_rx_mode,
++      .filter_config_ucast = &qed_configure_filter_ucast,
++      .filter_config_mcast = &qed_configure_filter_mcast,
+       .fastpath_stop = &qed_fastpath_stop,
+       .eth_cqe_completion = &qed_fp_cqe_completion,
+       .get_vport_stats = &qed_get_vport_stats,
+diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c
+index a2e4dfb5cb44..f99b085b56a5 100644
+--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
++++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
+@@ -619,30 +619,28 @@ static int qede_set_ucast_rx_mac(struct qede_dev *edev,
+                                enum qed_filter_xcast_params_type opcode,
+                                unsigned char mac[ETH_ALEN])
+ {
+-      struct qed_filter_params filter_cmd;
++      struct qed_filter_ucast_params ucast;
+-      memset(&filter_cmd, 0, sizeof(filter_cmd));
+-      filter_cmd.type = QED_FILTER_TYPE_UCAST;
+-      filter_cmd.filter.ucast.type = opcode;
+-      filter_cmd.filter.ucast.mac_valid = 1;
+-      ether_addr_copy(filter_cmd.filter.ucast.mac, mac);
++      memset(&ucast, 0, sizeof(ucast));
++      ucast.type = opcode;
++      ucast.mac_valid = 1;
++      ether_addr_copy(ucast.mac, mac);
+-      return edev->ops->filter_config(edev->cdev, &filter_cmd);
++      return edev->ops->filter_config_ucast(edev->cdev, &ucast);
+ }
+ static int qede_set_ucast_rx_vlan(struct qede_dev *edev,
+                                 enum qed_filter_xcast_params_type opcode,
+                                 u16 vid)
+ {
+-      struct qed_filter_params filter_cmd;
++      struct qed_filter_ucast_params ucast;
+-      memset(&filter_cmd, 0, sizeof(filter_cmd));
+-      filter_cmd.type = QED_FILTER_TYPE_UCAST;
+-      filter_cmd.filter.ucast.type = opcode;
+-      filter_cmd.filter.ucast.vlan_valid = 1;
+-      filter_cmd.filter.ucast.vlan = vid;
++      memset(&ucast, 0, sizeof(ucast));
++      ucast.type = opcode;
++      ucast.vlan_valid = 1;
++      ucast.vlan = vid;
+-      return edev->ops->filter_config(edev->cdev, &filter_cmd);
++      return edev->ops->filter_config_ucast(edev->cdev, &ucast);
+ }
+ static int qede_config_accept_any_vlan(struct qede_dev *edev, bool action)
+@@ -1057,18 +1055,17 @@ static int qede_set_mcast_rx_mac(struct qede_dev *edev,
+                                enum qed_filter_xcast_params_type opcode,
+                                unsigned char *mac, int num_macs)
+ {
+-      struct qed_filter_params filter_cmd;
++      struct qed_filter_mcast_params mcast;
+       int i;
+-      memset(&filter_cmd, 0, sizeof(filter_cmd));
+-      filter_cmd.type = QED_FILTER_TYPE_MCAST;
+-      filter_cmd.filter.mcast.type = opcode;
+-      filter_cmd.filter.mcast.num = num_macs;
++      memset(&mcast, 0, sizeof(mcast));
++      mcast.type = opcode;
++      mcast.num = num_macs;
+       for (i = 0; i < num_macs; i++, mac += ETH_ALEN)
+-              ether_addr_copy(filter_cmd.filter.mcast.mac[i], mac);
++              ether_addr_copy(mcast.mac[i], mac);
+-      return edev->ops->filter_config(edev->cdev, &filter_cmd);
++      return edev->ops->filter_config_mcast(edev->cdev, &mcast);
+ }
+ int qede_set_mac_addr(struct net_device *ndev, void *p)
+@@ -1194,7 +1191,6 @@ void qede_config_rx_mode(struct net_device *ndev)
+ {
+       enum qed_filter_rx_mode_type accept_flags;
+       struct qede_dev *edev = netdev_priv(ndev);
+-      struct qed_filter_params rx_mode;
+       unsigned char *uc_macs, *temp;
+       struct netdev_hw_addr *ha;
+       int rc, uc_count;
+@@ -1220,10 +1216,6 @@ void qede_config_rx_mode(struct net_device *ndev)
+       netif_addr_unlock_bh(ndev);
+-      /* Configure the struct for the Rx mode */
+-      memset(&rx_mode, 0, sizeof(struct qed_filter_params));
+-      rx_mode.type = QED_FILTER_TYPE_RX_MODE;
+-
+       /* Remove all previous unicast secondary macs and multicast macs
+        * (configure / leave the primary mac)
+        */
+@@ -1271,8 +1263,7 @@ void qede_config_rx_mode(struct net_device *ndev)
+               qede_config_accept_any_vlan(edev, false);
+       }
+-      rx_mode.filter.accept_flags = accept_flags;
+-      edev->ops->filter_config(edev->cdev, &rx_mode);
++      edev->ops->filter_config_rx_mode(edev->cdev, accept_flags);
+ out:
+       kfree(uc_macs);
+ }
+diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h
+index 812a4d751163..4df0bf0a0864 100644
+--- a/include/linux/qed/qed_eth_if.h
++++ b/include/linux/qed/qed_eth_if.h
+@@ -145,12 +145,6 @@ struct qed_filter_mcast_params {
+       unsigned char mac[64][ETH_ALEN];
+ };
+-union qed_filter_type_params {
+-      enum qed_filter_rx_mode_type accept_flags;
+-      struct qed_filter_ucast_params ucast;
+-      struct qed_filter_mcast_params mcast;
+-};
+-
+ enum qed_filter_type {
+       QED_FILTER_TYPE_UCAST,
+       QED_FILTER_TYPE_MCAST,
+@@ -158,11 +152,6 @@ enum qed_filter_type {
+       QED_MAX_FILTER_TYPES,
+ };
+-struct qed_filter_params {
+-      enum qed_filter_type type;
+-      union qed_filter_type_params filter;
+-};
+-
+ struct qed_tunn_params {
+       u16 vxlan_port;
+       u8 update_vxlan_port;
+@@ -314,8 +303,14 @@ struct qed_eth_ops {
+       int (*q_tx_stop)(struct qed_dev *cdev, u8 rss_id, void *handle);
+-      int (*filter_config)(struct qed_dev *cdev,
+-                           struct qed_filter_params *params);
++      int (*filter_config_rx_mode)(struct qed_dev *cdev,
++                                   enum qed_filter_rx_mode_type type);
++
++      int (*filter_config_ucast)(struct qed_dev *cdev,
++                                 struct qed_filter_ucast_params *params);
++
++      int (*filter_config_mcast)(struct qed_dev *cdev,
++                                 struct qed_filter_mcast_params *params);
+       int (*fastpath_stop)(struct qed_dev *cdev);
+-- 
+2.35.1
+
diff --git a/queue-5.15/risc-v-defconfigs-set-config_fb-y-for-fb-console.patch b/queue-5.15/risc-v-defconfigs-set-config_fb-y-for-fb-console.patch
new file mode 100644 (file)
index 0000000..d955657
--- /dev/null
@@ -0,0 +1,50 @@
+From 60ebac0790e3cdd61d8f3195025142ab92661ec3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Nov 2021 08:44:02 -0800
+Subject: RISC-V: defconfigs: Set CONFIG_FB=y, for FB console
+
+From: Palmer Dabbelt <palmer@rivosinc.com>
+
+[ Upstream commit 3d12b634fe8206ea974c6061a3f3eea529ffbc48 ]
+
+We have CONFIG_FRAMEBUFFER_CONSOLE=y in the defconfigs, but that depends
+on CONFIG_FB so it's not actually getting set.  I'm assuming most users
+on real systems want a framebuffer console, so this enables CONFIG_FB to
+allow that to take effect.
+
+Fixes: 33c57c0d3c67 ("RISC-V: Add a basic defconfig")
+Reviewed-by: Anup Patel <anup@brainfault.org>
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/configs/defconfig      | 1 +
+ arch/riscv/configs/rv32_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
+index c252fd5706d2..f2a2f9c9ed49 100644
+--- a/arch/riscv/configs/defconfig
++++ b/arch/riscv/configs/defconfig
+@@ -76,6 +76,7 @@ CONFIG_DRM=m
+ CONFIG_DRM_RADEON=m
+ CONFIG_DRM_NOUVEAU=m
+ CONFIG_DRM_VIRTIO_GPU=m
++CONFIG_FB=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_USB=y
+ CONFIG_USB_XHCI_HCD=y
+diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
+index 434ef5b64599..cdd113e7a291 100644
+--- a/arch/riscv/configs/rv32_defconfig
++++ b/arch/riscv/configs/rv32_defconfig
+@@ -71,6 +71,7 @@ CONFIG_POWER_RESET=y
+ CONFIG_DRM=y
+ CONFIG_DRM_RADEON=y
+ CONFIG_DRM_VIRTIO_GPU=y
++CONFIG_FB=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_USB=y
+ CONFIG_USB_XHCI_HCD=y
+-- 
+2.35.1
+
diff --git a/queue-5.15/riscv-defconfig-enable-drm_nouveau.patch b/queue-5.15/riscv-defconfig-enable-drm_nouveau.patch
new file mode 100644 (file)
index 0000000..96163c9
--- /dev/null
@@ -0,0 +1,43 @@
+From df87782aac9f7b585ff033d7c42ba8be13cbd16d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Oct 2021 18:46:58 +0200
+Subject: riscv: defconfig: enable DRM_NOUVEAU
+
+From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+
+[ Upstream commit ffa7a9141bb70702744a312f904b190ca064bdd7 ]
+
+Both RADEON and NOUVEAU graphics cards are supported on RISC-V. Enabling
+the one and not the other does not make sense.
+
+As typically at most one of RADEON, NOUVEAU, or VIRTIO GPU support will be
+needed DRM drivers should be compiled as modules.
+
+Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/configs/defconfig | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
+index 4ebc80315f01..c252fd5706d2 100644
+--- a/arch/riscv/configs/defconfig
++++ b/arch/riscv/configs/defconfig
+@@ -72,9 +72,10 @@ CONFIG_GPIOLIB=y
+ CONFIG_GPIO_SIFIVE=y
+ # CONFIG_PTP_1588_CLOCK is not set
+ CONFIG_POWER_RESET=y
+-CONFIG_DRM=y
+-CONFIG_DRM_RADEON=y
+-CONFIG_DRM_VIRTIO_GPU=y
++CONFIG_DRM=m
++CONFIG_DRM_RADEON=m
++CONFIG_DRM_NOUVEAU=m
++CONFIG_DRM_VIRTIO_GPU=m
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_USB=y
+ CONFIG_USB_XHCI_HCD=y
+-- 
+2.35.1
+
diff --git a/queue-5.15/riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch b/queue-5.15/riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch
new file mode 100644 (file)
index 0000000..232e5f4
--- /dev/null
@@ -0,0 +1,36 @@
+From 5fcee4219b77b08e315c1c97a1e9e3937575fb32 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Feb 2022 13:14:08 -0800
+Subject: riscv/mm: Add XIP_FIXUP for riscv_pfn_base
+
+From: Palmer Dabbelt <palmer@rivosinc.com>
+
+[ Upstream commit ca0cb9a60f6d86d4b2139c6f393a78f39edcd7cb ]
+
+This manifests as a crash early in boot on VexRiscv.
+
+Signed-off-by: Myrtle Shah <gatecat@ds0.me>
+[Palmer: split commit]
+Fixes: 44c922572952 ("RISC-V: enable XIP")
+Cc: stable@vger.kernel.org
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/mm/init.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index 7f130ac3b9f9..c58a7c77989b 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -265,6 +265,7 @@ pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
+ static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
+ #ifdef CONFIG_XIP_KERNEL
++#define riscv_pfn_base         (*(unsigned long  *)XIP_FIXUP(&riscv_pfn_base))
+ #define trampoline_pg_dir      ((pgd_t *)XIP_FIXUP(trampoline_pg_dir))
+ #define fixmap_pte             ((pte_t *)XIP_FIXUP(fixmap_pte))
+ #define early_pg_dir           ((pgd_t *)XIP_FIXUP(early_pg_dir))
+-- 
+2.35.1
+
diff --git a/queue-5.15/rxrpc-fix-locking-issue.patch b/queue-5.15/rxrpc-fix-locking-issue.patch
new file mode 100644 (file)
index 0000000..c835651
--- /dev/null
@@ -0,0 +1,278 @@
+From 6c69b2ec22827f6af9b763afbd7a393864949492 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 21 May 2022 08:45:28 +0100
+Subject: rxrpc: Fix locking issue
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit ad25f5cb39872ca14bcbe00816ae65c22fe04b89 ]
+
+There's a locking issue with the per-netns list of calls in rxrpc.  The
+pieces of code that add and remove a call from the list use write_lock()
+and the calls procfile uses read_lock() to access it.  However, the timer
+callback function may trigger a removal by trying to queue a call for
+processing and finding that it's already queued - at which point it has a
+spare refcount that it has to do something with.  Unfortunately, if it puts
+the call and this reduces the refcount to 0, the call will be removed from
+the list.  Unfortunately, since the _bh variants of the locking functions
+aren't used, this can deadlock.
+
+================================
+WARNING: inconsistent lock state
+5.18.0-rc3-build4+ #10 Not tainted
+--------------------------------
+inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
+ksoftirqd/2/25 [HC0[0]:SC1[1]:HE1:SE0] takes:
+ffff888107ac4038 (&rxnet->call_lock){+.?.}-{2:2}, at: rxrpc_put_call+0x103/0x14b
+{SOFTIRQ-ON-W} state was registered at:
+...
+ Possible unsafe locking scenario:
+
+       CPU0
+       ----
+  lock(&rxnet->call_lock);
+  <Interrupt>
+    lock(&rxnet->call_lock);
+
+ *** DEADLOCK ***
+
+1 lock held by ksoftirqd/2/25:
+ #0: ffff8881008ffdb0 ((&call->timer)){+.-.}-{0:0}, at: call_timer_fn+0x5/0x23d
+
+Changes
+=======
+ver #2)
+ - Changed to using list_next_rcu() rather than rcu_dereference() directly.
+
+Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Marc Dionne <marc.dionne@auristor.com>
+cc: linux-afs@lists.infradead.org
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/seq_file.c            | 32 ++++++++++++++++++++++++++++++++
+ include/linux/list.h     | 10 ++++++++++
+ include/linux/seq_file.h |  4 ++++
+ net/rxrpc/ar-internal.h  |  2 +-
+ net/rxrpc/call_accept.c  |  6 +++---
+ net/rxrpc/call_object.c  | 18 +++++++++---------
+ net/rxrpc/net_ns.c       |  2 +-
+ net/rxrpc/proc.c         | 10 ++--------
+ 8 files changed, 62 insertions(+), 22 deletions(-)
+
+diff --git a/fs/seq_file.c b/fs/seq_file.c
+index 4a2cda04d3e2..b17ee4c4f618 100644
+--- a/fs/seq_file.c
++++ b/fs/seq_file.c
+@@ -947,6 +947,38 @@ struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
+ }
+ EXPORT_SYMBOL(seq_list_next);
++struct list_head *seq_list_start_rcu(struct list_head *head, loff_t pos)
++{
++      struct list_head *lh;
++
++      list_for_each_rcu(lh, head)
++              if (pos-- == 0)
++                      return lh;
++
++      return NULL;
++}
++EXPORT_SYMBOL(seq_list_start_rcu);
++
++struct list_head *seq_list_start_head_rcu(struct list_head *head, loff_t pos)
++{
++      if (!pos)
++              return head;
++
++      return seq_list_start_rcu(head, pos - 1);
++}
++EXPORT_SYMBOL(seq_list_start_head_rcu);
++
++struct list_head *seq_list_next_rcu(void *v, struct list_head *head,
++                                  loff_t *ppos)
++{
++      struct list_head *lh;
++
++      lh = list_next_rcu((struct list_head *)v);
++      ++*ppos;
++      return lh == head ? NULL : lh;
++}
++EXPORT_SYMBOL(seq_list_next_rcu);
++
+ /**
+  * seq_hlist_start - start an iteration of a hlist
+  * @head: the head of the hlist
+diff --git a/include/linux/list.h b/include/linux/list.h
+index a119dd1990d4..d206ae93c06d 100644
+--- a/include/linux/list.h
++++ b/include/linux/list.h
+@@ -577,6 +577,16 @@ static inline void list_splice_tail_init(struct list_head *list,
+ #define list_for_each(pos, head) \
+       for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
++/**
++ * list_for_each_rcu - Iterate over a list in an RCU-safe fashion
++ * @pos:      the &struct list_head to use as a loop cursor.
++ * @head:     the head for your list.
++ */
++#define list_for_each_rcu(pos, head)            \
++      for (pos = rcu_dereference((head)->next); \
++           !list_is_head(pos, (head)); \
++           pos = rcu_dereference(pos->next))
++
+ /**
+  * list_for_each_continue - continue iteration over a list
+  * @pos:      the &struct list_head to use as a loop cursor.
+diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
+index 5733890df64f..0b429111f85e 100644
+--- a/include/linux/seq_file.h
++++ b/include/linux/seq_file.h
+@@ -261,6 +261,10 @@ extern struct list_head *seq_list_start_head(struct list_head *head,
+ extern struct list_head *seq_list_next(void *v, struct list_head *head,
+               loff_t *ppos);
++extern struct list_head *seq_list_start_rcu(struct list_head *head, loff_t pos);
++extern struct list_head *seq_list_start_head_rcu(struct list_head *head, loff_t pos);
++extern struct list_head *seq_list_next_rcu(void *v, struct list_head *head, loff_t *ppos);
++
+ /*
+  * Helpers for iteration over hlist_head-s in seq_files
+  */
+diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
+index dce056adb78c..f2d593e27b64 100644
+--- a/net/rxrpc/ar-internal.h
++++ b/net/rxrpc/ar-internal.h
+@@ -68,7 +68,7 @@ struct rxrpc_net {
+       struct proc_dir_entry   *proc_net;      /* Subdir in /proc/net */
+       u32                     epoch;          /* Local epoch for detecting local-end reset */
+       struct list_head        calls;          /* List of calls active in this namespace */
+-      rwlock_t                call_lock;      /* Lock for ->calls */
++      spinlock_t              call_lock;      /* Lock for ->calls */
+       atomic_t                nr_calls;       /* Count of allocated calls */
+       atomic_t                nr_conns;
+diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
+index 1ae90fb97936..8b24ffbc72ef 100644
+--- a/net/rxrpc/call_accept.c
++++ b/net/rxrpc/call_accept.c
+@@ -140,9 +140,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
+       write_unlock(&rx->call_lock);
+       rxnet = call->rxnet;
+-      write_lock(&rxnet->call_lock);
+-      list_add_tail(&call->link, &rxnet->calls);
+-      write_unlock(&rxnet->call_lock);
++      spin_lock_bh(&rxnet->call_lock);
++      list_add_tail_rcu(&call->link, &rxnet->calls);
++      spin_unlock_bh(&rxnet->call_lock);
+       b->call_backlog[call_head] = call;
+       smp_store_release(&b->call_backlog_head, (call_head + 1) & (size - 1));
+diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
+index 043508fd8d8a..25c9a2cbf048 100644
+--- a/net/rxrpc/call_object.c
++++ b/net/rxrpc/call_object.c
+@@ -337,9 +337,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
+       write_unlock(&rx->call_lock);
+       rxnet = call->rxnet;
+-      write_lock(&rxnet->call_lock);
+-      list_add_tail(&call->link, &rxnet->calls);
+-      write_unlock(&rxnet->call_lock);
++      spin_lock_bh(&rxnet->call_lock);
++      list_add_tail_rcu(&call->link, &rxnet->calls);
++      spin_unlock_bh(&rxnet->call_lock);
+       /* From this point on, the call is protected by its own lock. */
+       release_sock(&rx->sk);
+@@ -631,9 +631,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
+               ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
+               if (!list_empty(&call->link)) {
+-                      write_lock(&rxnet->call_lock);
++                      spin_lock_bh(&rxnet->call_lock);
+                       list_del_init(&call->link);
+-                      write_unlock(&rxnet->call_lock);
++                      spin_unlock_bh(&rxnet->call_lock);
+               }
+               rxrpc_cleanup_call(call);
+@@ -705,7 +705,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
+       _enter("");
+       if (!list_empty(&rxnet->calls)) {
+-              write_lock(&rxnet->call_lock);
++              spin_lock_bh(&rxnet->call_lock);
+               while (!list_empty(&rxnet->calls)) {
+                       call = list_entry(rxnet->calls.next,
+@@ -720,12 +720,12 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
+                              rxrpc_call_states[call->state],
+                              call->flags, call->events);
+-                      write_unlock(&rxnet->call_lock);
++                      spin_unlock_bh(&rxnet->call_lock);
+                       cond_resched();
+-                      write_lock(&rxnet->call_lock);
++                      spin_lock_bh(&rxnet->call_lock);
+               }
+-              write_unlock(&rxnet->call_lock);
++              spin_unlock_bh(&rxnet->call_lock);
+       }
+       atomic_dec(&rxnet->nr_calls);
+diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c
+index cc7e30733feb..e4d6d432515b 100644
+--- a/net/rxrpc/net_ns.c
++++ b/net/rxrpc/net_ns.c
+@@ -50,7 +50,7 @@ static __net_init int rxrpc_init_net(struct net *net)
+       rxnet->epoch |= RXRPC_RANDOM_EPOCH;
+       INIT_LIST_HEAD(&rxnet->calls);
+-      rwlock_init(&rxnet->call_lock);
++      spin_lock_init(&rxnet->call_lock);
+       atomic_set(&rxnet->nr_calls, 1);
+       atomic_set(&rxnet->nr_conns, 1);
+diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
+index e2f990754f88..5a67955cc00f 100644
+--- a/net/rxrpc/proc.c
++++ b/net/rxrpc/proc.c
+@@ -26,29 +26,23 @@ static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
+  */
+ static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
+       __acquires(rcu)
+-      __acquires(rxnet->call_lock)
+ {
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+       rcu_read_lock();
+-      read_lock(&rxnet->call_lock);
+-      return seq_list_start_head(&rxnet->calls, *_pos);
++      return seq_list_start_head_rcu(&rxnet->calls, *_pos);
+ }
+ static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ {
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+-      return seq_list_next(v, &rxnet->calls, pos);
++      return seq_list_next_rcu(v, &rxnet->calls, pos);
+ }
+ static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
+-      __releases(rxnet->call_lock)
+       __releases(rcu)
+ {
+-      struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+-
+-      read_unlock(&rxnet->call_lock);
+       rcu_read_unlock();
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/s390-boot-allocate-amode31-section-in-decompressor.patch b/queue-5.15/s390-boot-allocate-amode31-section-in-decompressor.patch
new file mode 100644 (file)
index 0000000..54a698a
--- /dev/null
@@ -0,0 +1,156 @@
+From 0001f7eab67a67000c3c1f01f6c059320bccef7c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 Sep 2021 14:18:26 +0200
+Subject: s390/boot: allocate amode31 section in decompressor
+
+From: Alexander Gordeev <agordeev@linux.ibm.com>
+
+[ Upstream commit e3ec8e0f5711d73f7e5d5c3cffdf4fad4f1487b9 ]
+
+The memory for amode31 section is allocated from the decompressed
+kernel. Instead, allocate that memory from the decompressor. This
+is a prerequisite to allow initialization of the virtual memory
+before the decompressed kernel takes over.
+
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/boot/compressed/decompressor.h |  1 +
+ arch/s390/boot/startup.c                 |  8 ++++++++
+ arch/s390/kernel/entry.h                 |  1 +
+ arch/s390/kernel/setup.c                 | 22 +++++++++-------------
+ arch/s390/kernel/vmlinux.lds.S           |  1 +
+ 5 files changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/arch/s390/boot/compressed/decompressor.h b/arch/s390/boot/compressed/decompressor.h
+index a59f75c5b049..f75cc31a77dd 100644
+--- a/arch/s390/boot/compressed/decompressor.h
++++ b/arch/s390/boot/compressed/decompressor.h
+@@ -24,6 +24,7 @@ struct vmlinux_info {
+       unsigned long dynsym_start;
+       unsigned long rela_dyn_start;
+       unsigned long rela_dyn_end;
++      unsigned long amode31_size;
+ };
+ /* Symbols defined by linker scripts */
+diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
+index b13352dd1e1c..1aa11a8f57dd 100644
+--- a/arch/s390/boot/startup.c
++++ b/arch/s390/boot/startup.c
+@@ -15,6 +15,7 @@
+ #include "uv.h"
+ unsigned long __bootdata_preserved(__kaslr_offset);
++unsigned long __bootdata(__amode31_base);
+ unsigned long __bootdata_preserved(VMALLOC_START);
+ unsigned long __bootdata_preserved(VMALLOC_END);
+ struct page *__bootdata_preserved(vmemmap);
+@@ -233,6 +234,12 @@ static void offset_vmlinux_info(unsigned long offset)
+       vmlinux.dynsym_start += offset;
+ }
++static unsigned long reserve_amode31(unsigned long safe_addr)
++{
++      __amode31_base = PAGE_ALIGN(safe_addr);
++      return safe_addr + vmlinux.amode31_size;
++}
++
+ void startup_kernel(void)
+ {
+       unsigned long random_lma;
+@@ -247,6 +254,7 @@ void startup_kernel(void)
+       setup_lpp();
+       store_ipl_parmblock();
+       safe_addr = mem_safe_offset();
++      safe_addr = reserve_amode31(safe_addr);
+       safe_addr = read_ipl_report(safe_addr);
+       uv_query_info();
+       rescue_initrd(safe_addr);
+diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
+index 7f2696e8d511..6083090be1f4 100644
+--- a/arch/s390/kernel/entry.h
++++ b/arch/s390/kernel/entry.h
+@@ -70,5 +70,6 @@ extern struct exception_table_entry _stop_amode31_ex_table[];
+ #define __amode31_data __section(".amode31.data")
+ #define __amode31_ref __section(".amode31.refs")
+ extern long _start_amode31_refs[], _end_amode31_refs[];
++extern unsigned long __amode31_base;
+ #endif /* _ENTRY_H */
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index 8ede12c4ba6b..e38de9e8ee13 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -95,10 +95,10 @@ EXPORT_SYMBOL(console_irq);
+  * relocated above 2 GB, because it has to use 31 bit addresses.
+  * Such code and data is part of the .amode31 section.
+  */
+-unsigned long __amode31_ref __samode31 = __pa(&_samode31);
+-unsigned long __amode31_ref __eamode31 = __pa(&_eamode31);
+-unsigned long __amode31_ref __stext_amode31 = __pa(&_stext_amode31);
+-unsigned long __amode31_ref __etext_amode31 = __pa(&_etext_amode31);
++unsigned long __amode31_ref __samode31 = (unsigned long)&_samode31;
++unsigned long __amode31_ref __eamode31 = (unsigned long)&_eamode31;
++unsigned long __amode31_ref __stext_amode31 = (unsigned long)&_stext_amode31;
++unsigned long __amode31_ref __etext_amode31 = (unsigned long)&_etext_amode31;
+ struct exception_table_entry __amode31_ref *__start_amode31_ex_table = _start_amode31_ex_table;
+ struct exception_table_entry __amode31_ref *__stop_amode31_ex_table = _stop_amode31_ex_table;
+@@ -149,6 +149,7 @@ struct mem_detect_info __bootdata(mem_detect);
+ struct initrd_data __bootdata(initrd_data);
+ unsigned long __bootdata_preserved(__kaslr_offset);
++unsigned long __bootdata(__amode31_base);
+ unsigned int __bootdata_preserved(zlib_dfltcc_support);
+ EXPORT_SYMBOL(zlib_dfltcc_support);
+ u64 __bootdata_preserved(stfle_fac_list[16]);
+@@ -800,6 +801,7 @@ static void __init reserve_kernel(void)
+       memblock_reserve(0, STARTUP_NORMAL_OFFSET);
+       memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP);
++      memblock_reserve(__amode31_base, __eamode31 - __samode31);
+       memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
+                        - (unsigned long)_stext);
+ }
+@@ -820,20 +822,14 @@ static void __init setup_memory(void)
+ static void __init relocate_amode31_section(void)
+ {
+-      unsigned long amode31_addr, amode31_size;
+-      long amode31_offset;
++      unsigned long amode31_size = __eamode31 - __samode31;
++      long amode31_offset = __amode31_base - __samode31;
+       long *ptr;
+-      /* Allocate a new AMODE31 capable memory region */
+-      amode31_size = __eamode31 - __samode31;
+       pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size);
+-      amode31_addr = (unsigned long)memblock_alloc_low(amode31_size, PAGE_SIZE);
+-      if (!amode31_addr)
+-              panic("Failed to allocate memory for AMODE31 section\n");
+-      amode31_offset = amode31_addr - __samode31;
+       /* Move original AMODE31 section to the new one */
+-      memmove((void *)amode31_addr, (void *)__samode31, amode31_size);
++      memmove((void *)__amode31_base, (void *)__samode31, amode31_size);
+       /* Zero out the old AMODE31 section to catch invalid accesses within it */
+       memset((void *)__samode31, 0, amode31_size);
+diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
+index 63bdb9e1bfc1..42c43521878f 100644
+--- a/arch/s390/kernel/vmlinux.lds.S
++++ b/arch/s390/kernel/vmlinux.lds.S
+@@ -212,6 +212,7 @@ SECTIONS
+               QUAD(__dynsym_start)                            /* dynsym_start */
+               QUAD(__rela_dyn_start)                          /* rela_dyn_start */
+               QUAD(__rela_dyn_end)                            /* rela_dyn_end */
++              QUAD(_eamode31 - _samode31)                     /* amode31_size */
+       } :NONE
+       /* Debugging sections.  */
+-- 
+2.35.1
+
diff --git a/queue-5.15/s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch b/queue-5.15/s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch
new file mode 100644 (file)
index 0000000..b20a601
--- /dev/null
@@ -0,0 +1,40 @@
+From ce1ab2ca6f876edd9c3118d16224e046ceb7c313 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 9 Feb 2022 11:25:09 +0100
+Subject: s390/setup: preserve memory at OLDMEM_BASE and OLDMEM_SIZE
+
+From: Alexander Egorenkov <egorenar@linux.ibm.com>
+
+[ Upstream commit 6b4b54c7ca347bcb4aa7a3cc01aa16e84ac7fbe4 ]
+
+We need to preserve the values at OLDMEM_BASE and OLDMEM_SIZE which are
+used by zgetdump in case when kdump crashes. In that case zgetdump will
+attempt to read OLDMEM_BASE and OLDMEM_SIZE in order to find out where
+the memory range [0 - OLDMEM_SIZE] belonging to the production kernel is.
+
+Fixes: f1a546947431 ("s390/setup: don't reserve memory that occupied decompressor's head")
+Cc: stable@vger.kernel.org # 5.15+
+Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
+Acked-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/setup.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index 2ebde341d057..36c1f31dfd66 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -798,6 +798,8 @@ static void __init check_initrd(void)
+ static void __init reserve_kernel(void)
+ {
+       memblock_reserve(0, STARTUP_NORMAL_OFFSET);
++      memblock_reserve(OLDMEM_BASE, sizeof(unsigned long));
++      memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long));
+       memblock_reserve(__amode31_base, __eamode31 - __samode31);
+       memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP);
+       memblock_reserve(__pa(_stext), _end - _stext);
+-- 
+2.35.1
+
diff --git a/queue-5.15/s390-setup-use-physical-pointers-for-memblock_reserv.patch b/queue-5.15/s390-setup-use-physical-pointers-for-memblock_reserv.patch
new file mode 100644 (file)
index 0000000..2656b87
--- /dev/null
@@ -0,0 +1,43 @@
+From 71a90551a633bf62bef091dd671959717a2a2932 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 Jan 2021 13:06:02 +0100
+Subject: s390/setup: use physical pointers for memblock_reserve()
+
+From: Alexander Gordeev <agordeev@linux.ibm.com>
+
+[ Upstream commit 04f11ed7d8e018e1f01ebda5814ddfeb3a1e6ae1 ]
+
+memblock_reserve() function accepts physcal address of a memory
+block to be reserved, but provided with virtual memory pointers.
+
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/kernel/setup.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index e38de9e8ee13..2ebde341d057 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -797,13 +797,10 @@ static void __init check_initrd(void)
+  */
+ static void __init reserve_kernel(void)
+ {
+-      unsigned long start_pfn = PFN_UP(__pa(_end));
+-
+       memblock_reserve(0, STARTUP_NORMAL_OFFSET);
+-      memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP);
+       memblock_reserve(__amode31_base, __eamode31 - __samode31);
+-      memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
+-                       - (unsigned long)_stext);
++      memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP);
++      memblock_reserve(__pa(_stext), _end - _stext);
+ }
+ static void __init setup_memory(void)
+-- 
+2.35.1
+
diff --git a/queue-5.15/scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch b/queue-5.15/scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch
new file mode 100644 (file)
index 0000000..d78c050
--- /dev/null
@@ -0,0 +1,145 @@
+From bbde4623d891f1ffb9444969baf72dbdc6dcd606 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 26 Oct 2021 04:54:06 -0700
+Subject: scsi: qla2xxx: edif: Replace list_for_each_safe with
+ list_for_each_entry_safe
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 8062b742d3bd336ca10ab5a1db1629d33700f9c6 ]
+
+This patch is per review comment by Hannes Reinecke from previous
+submission to replace list_for_each_safe with list_for_each_entry_safe.
+
+Link: https://lore.kernel.org/r/20211026115412.27691-8-njavali@marvell.com
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_edif.c | 39 ++++++++-------------------------
+ drivers/scsi/qla2xxx/qla_edif.h |  1 -
+ drivers/scsi/qla2xxx/qla_os.c   |  8 +++----
+ 3 files changed, 13 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
+index a00fe88c6021..e40b9cc38214 100644
+--- a/drivers/scsi/qla2xxx/qla_edif.c
++++ b/drivers/scsi/qla2xxx/qla_edif.c
+@@ -1684,41 +1684,25 @@ static struct enode *
+ qla_enode_find(scsi_qla_host_t *vha, uint32_t ntype, uint32_t p1, uint32_t p2)
+ {
+       struct enode            *node_rtn = NULL;
+-      struct enode            *list_node = NULL;
++      struct enode            *list_node, *q;
+       unsigned long           flags;
+-      struct list_head        *pos, *q;
+       uint32_t                sid;
+-      uint32_t                rw_flag;
+       struct purexevent       *purex;
+       /* secure the list from moving under us */
+       spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
+-      list_for_each_safe(pos, q, &vha->pur_cinfo.head) {
+-              list_node = list_entry(pos, struct enode, list);
++      list_for_each_entry_safe(list_node, q, &vha->pur_cinfo.head, list) {
+               /* node type determines what p1 and p2 are */
+               purex = &list_node->u.purexinfo;
+               sid = p1;
+-              rw_flag = p2;
+               if (purex->pur_info.pur_sid.b24 == sid) {
+-                      if (purex->pur_info.pur_pend == 1 &&
+-                          rw_flag == PUR_GET) {
+-                              /*
+-                               * if the receive is in progress
+-                               * and its a read/get then can't
+-                               * transfer yet
+-                               */
+-                              ql_dbg(ql_dbg_edif, vha, 0x9106,
+-                                  "%s purex xfer in progress for sid=%x\n",
+-                                  __func__, sid);
+-                      } else {
+-                              /* found it and its complete */
+-                              node_rtn = list_node;
+-                              list_del(pos);
+-                              break;
+-                      }
++                      /* found it and its complete */
++                      node_rtn = list_node;
++                      list_del(&list_node->list);
++                      break;
+               }
+       }
+@@ -2428,7 +2412,6 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
+       purex = &ptr->u.purexinfo;
+       purex->pur_info.pur_sid = a.did;
+-      purex->pur_info.pur_pend = 0;
+       purex->pur_info.pur_bytes_rcvd = totlen;
+       purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
+       purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
+@@ -3180,18 +3163,14 @@ static uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport,
+ /* release any sadb entries -- only done at teardown */
+ void qla_edif_sadb_release(struct qla_hw_data *ha)
+ {
+-      struct list_head *pos;
+-      struct list_head *tmp;
+-      struct edif_sa_index_entry *entry;
++      struct edif_sa_index_entry *entry, *tmp;
+-      list_for_each_safe(pos, tmp, &ha->sadb_rx_index_list) {
+-              entry = list_entry(pos, struct edif_sa_index_entry, next);
++      list_for_each_entry_safe(entry, tmp, &ha->sadb_rx_index_list, next) {
+               list_del(&entry->next);
+               kfree(entry);
+       }
+-      list_for_each_safe(pos, tmp, &ha->sadb_tx_index_list) {
+-              entry = list_entry(pos, struct edif_sa_index_entry, next);
++      list_for_each_entry_safe(entry, tmp, &ha->sadb_tx_index_list, next) {
+               list_del(&entry->next);
+               kfree(entry);
+       }
+diff --git a/drivers/scsi/qla2xxx/qla_edif.h b/drivers/scsi/qla2xxx/qla_edif.h
+index 45cf87e33778..32800bfb32a3 100644
+--- a/drivers/scsi/qla2xxx/qla_edif.h
++++ b/drivers/scsi/qla2xxx/qla_edif.h
+@@ -101,7 +101,6 @@ struct dinfo {
+ };
+ struct pur_ninfo {
+-      unsigned int    pur_pend:1;
+       port_id_t       pur_sid;
+       port_id_t       pur_did;
+       uint8_t         vp_idx;
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index 12958aea893f..c7ab8a8be24c 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -3886,13 +3886,13 @@ qla2x00_remove_one(struct pci_dev *pdev)
+ static inline void
+ qla24xx_free_purex_list(struct purex_list *list)
+ {
+-      struct list_head *item, *next;
++      struct purex_item *item, *next;
+       ulong flags;
+       spin_lock_irqsave(&list->lock, flags);
+-      list_for_each_safe(item, next, &list->head) {
+-              list_del(item);
+-              kfree(list_entry(item, struct purex_item, list));
++      list_for_each_entry_safe(item, next, &list->head, list) {
++              list_del(&item->list);
++              kfree(item);
+       }
+       spin_unlock_irqrestore(&list->lock, flags);
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch b/queue-5.15/scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch
new file mode 100644 (file)
index 0000000..212cb12
--- /dev/null
@@ -0,0 +1,63 @@
+From 5486a36c77b7c513bc8e7ee7f5efb2f25bbec26a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Mar 2022 01:25:56 -0800
+Subject: scsi: qla2xxx: Fix crash during module load unload test
+
+From: Arun Easi <aeasi@marvell.com>
+
+[ Upstream commit 0972252450f90db56dd5415a20e2aec21a08d036 ]
+
+During purex packet handling the driver was incorrectly freeing a
+pre-allocated structure. Fix this by skipping that entry.
+
+System crashed with the following stack during a module unload test.
+
+Call Trace:
+       sbitmap_init_node+0x7f/0x1e0
+       sbitmap_queue_init_node+0x24/0x150
+       blk_mq_init_bitmaps+0x3d/0xa0
+       blk_mq_init_tags+0x68/0x90
+       blk_mq_alloc_map_and_rqs+0x44/0x120
+       blk_mq_alloc_set_map_and_rqs+0x63/0x150
+       blk_mq_alloc_tag_set+0x11b/0x230
+       scsi_add_host_with_dma.cold+0x3f/0x245
+       qla2x00_probe_one+0xd5a/0x1b80 [qla2xxx]
+
+Call Trace with slub_debug and debug kernel:
+       kasan_report_invalid_free+0x50/0x80
+       __kasan_slab_free+0x137/0x150
+       slab_free_freelist_hook+0xc6/0x190
+       kfree+0xe8/0x2e0
+       qla2x00_free_device+0x3bb/0x5d0 [qla2xxx]
+       qla2x00_remove_one+0x668/0xcf0 [qla2xxx]
+
+Link: https://lore.kernel.org/r/20220310092604.22950-6-njavali@marvell.com
+Fixes: 62e9dd177732 ("scsi: qla2xxx: Change in PUREX to handle FPIN ELS requests")
+Cc: stable@vger.kernel.org
+Reported-by: Marco Patalano <mpatalan@redhat.com>
+Tested-by: Marco Patalano <mpatalan@redhat.com>
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Arun Easi <aeasi@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_os.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index c7ab8a8be24c..e683b1c01c9f 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -3892,6 +3892,8 @@ qla24xx_free_purex_list(struct purex_list *list)
+       spin_lock_irqsave(&list->lock, flags);
+       list_for_each_entry_safe(item, next, &list->head, list) {
+               list_del(&item->list);
++              if (item == &item->vha->default_item)
++                      continue;
+               kfree(item);
+       }
+       spin_unlock_irqrestore(&list->lock, flags);
+-- 
+2.35.1
+
diff --git a/queue-5.15/scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch b/queue-5.15/scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch
new file mode 100644 (file)
index 0000000..14c8bd8
--- /dev/null
@@ -0,0 +1,99 @@
+From 38ec01bdbe4dc6581768c5f268071e0427f6ef3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Mar 2022 01:25:59 -0800
+Subject: scsi: qla2xxx: Fix laggy FC remote port session recovery
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 713b415726f100f6644971e75ebfe1edbef1a390 ]
+
+For session recovery, driver relies on the dpc thread to initiate certain
+operations. The dpc thread runs exclusively without the Mailbox interface
+being occupied. A recent code change for heartbeat check via mailbox cmd 0
+is preventing the dpc thread from carrying out its operation. This patch
+allows the higher priority error recovery to run first before running the
+lower priority heartbeat check.
+
+Link: https://lore.kernel.org/r/20220310092604.22950-9-njavali@marvell.com
+Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check")
+Cc: stable@vger.kernel.org
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h |  1 +
+ drivers/scsi/qla2xxx/qla_os.c  | 20 +++++++++++++++++---
+ 2 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 0589ab8e6467..303ad60d1d49 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -4621,6 +4621,7 @@ struct qla_hw_data {
+       struct workqueue_struct *wq;
+       struct work_struct heartbeat_work;
+       struct qlfc_fw fw_buf;
++      unsigned long last_heartbeat_run_jiffies;
+       /* FCP_CMND priority support */
+       struct qla_fcp_prio_cfg *fcp_prio_cfg;
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index b224326bacee..12958aea893f 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -7205,7 +7205,7 @@ static bool qla_do_heartbeat(struct scsi_qla_host *vha)
+       return do_heartbeat;
+ }
+-static void qla_heart_beat(struct scsi_qla_host *vha)
++static void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started)
+ {
+       struct qla_hw_data *ha = vha->hw;
+@@ -7215,8 +7215,19 @@ static void qla_heart_beat(struct scsi_qla_host *vha)
+       if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha))
+               return;
+-      if (qla_do_heartbeat(vha))
++      /*
++       * dpc thread cannot run if heartbeat is running at the same time.
++       * We also do not want to starve heartbeat task. Therefore, do
++       * heartbeat task at least once every 5 seconds.
++       */
++      if (dpc_started &&
++          time_before(jiffies, ha->last_heartbeat_run_jiffies + 5 * HZ))
++              return;
++
++      if (qla_do_heartbeat(vha)) {
++              ha->last_heartbeat_run_jiffies = jiffies;
+               queue_work(ha->wq, &ha->heartbeat_work);
++      }
+ }
+ /**************************************************************************
+@@ -7407,6 +7418,8 @@ qla2x00_timer(struct timer_list *t)
+               start_dpc++;
+       }
++      /* borrowing w to signify dpc will run */
++      w = 0;
+       /* Schedule the DPC routine if needed */
+       if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+           test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) ||
+@@ -7439,9 +7452,10 @@ qla2x00_timer(struct timer_list *t)
+                   test_bit(RELOGIN_NEEDED, &vha->dpc_flags),
+                   test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags));
+               qla2xxx_wake_dpc(vha);
++              w = 1;
+       }
+-      qla_heart_beat(vha);
++      qla_heart_beat(vha, w);
+       qla2x00_restart_timer(vha, WATCH_INTERVAL);
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch b/queue-5.15/scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch
new file mode 100644 (file)
index 0000000..202158c
--- /dev/null
@@ -0,0 +1,74 @@
+From 008496d3d83efaa493b531b6f998f9b902322282 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Mar 2022 01:25:54 -0800
+Subject: scsi: qla2xxx: Fix loss of NVMe namespaces after driver reload test
+
+From: Arun Easi <aeasi@marvell.com>
+
+[ Upstream commit db212f2eb3fb7f546366777e93c8f54614d39269 ]
+
+Driver registration of localport can race when it happens at the remote
+port discovery time. Fix this by calling the registration under a mutex.
+
+Link: https://lore.kernel.org/r/20220310092604.22950-4-njavali@marvell.com
+Fixes: e84067d74301 ("scsi: qla2xxx: Add FC-NVMe F/W initialization and transport registration")
+Cc: stable@vger.kernel.org
+Reported-by: Marco Patalano <mpatalan@redhat.com>
+Tested-by: Marco Patalano <mpatalan@redhat.com>
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Arun Easi <aeasi@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_nvme.c | 27 +++++++++++++++++++--------
+ 1 file changed, 19 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
+index 42b29f4fd937..1bf3ab10846a 100644
+--- a/drivers/scsi/qla2xxx/qla_nvme.c
++++ b/drivers/scsi/qla2xxx/qla_nvme.c
+@@ -775,7 +775,6 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
+       ha = vha->hw;
+       tmpl = &qla_nvme_fc_transport;
+-      WARN_ON(vha->nvme_local_port);
+       qla_nvme_fc_transport.max_hw_queues =
+           min((uint8_t)(qla_nvme_fc_transport.max_hw_queues),
+@@ -786,13 +785,25 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
+       pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR;
+       pinfo.port_id = vha->d_id.b24;
+-      ql_log(ql_log_info, vha, 0xffff,
+-          "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
+-          pinfo.node_name, pinfo.port_name, pinfo.port_id);
+-      qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary;
+-
+-      ret = nvme_fc_register_localport(&pinfo, tmpl,
+-          get_device(&ha->pdev->dev), &vha->nvme_local_port);
++      mutex_lock(&ha->vport_lock);
++      /*
++       * Check again for nvme_local_port to see if any other thread raced
++       * with this one and finished registration.
++       */
++      if (!vha->nvme_local_port) {
++              ql_log(ql_log_info, vha, 0xffff,
++                  "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
++                  pinfo.node_name, pinfo.port_name, pinfo.port_id);
++              qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary;
++
++              ret = nvme_fc_register_localport(&pinfo, tmpl,
++                                               get_device(&ha->pdev->dev),
++                                               &vha->nvme_local_port);
++              mutex_unlock(&ha->vport_lock);
++      } else {
++              mutex_unlock(&ha->vport_lock);
++              return 0;
++      }
+       if (ret) {
+               ql_log(ql_log_warn, vha, 0xffff,
+                   "register_localport failed: ret=%x\n", ret);
+-- 
+2.35.1
+
diff --git a/queue-5.15/scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch b/queue-5.15/scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch
new file mode 100644 (file)
index 0000000..d928782
--- /dev/null
@@ -0,0 +1,219 @@
+From c6c065c3f8b75d197175726efac829397a77e4c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Sep 2021 09:46:20 -0700
+Subject: scsi: qla2xxx: Move heartbeat handling from DPC thread to workqueue
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Manish Rangankar <mrangankar@marvell.com>
+
+[ Upstream commit 3a4e1f3b3a3c733de3b82b9b522e54803e1165ae ]
+
+DPC thread gets restricted due to a no-op mailbox, which is a blocking call
+and has a high execution frequency. To free up the DPC thread we move no-op
+handling to the workqueue. Also, modified qla_do_heartbeat() to send no-op
+MBC if we don’t have any active interrupts, but there are still I/Os
+outstanding with firmware.
+
+Link: https://lore.kernel.org/r/20210908164622.19240-9-njavali@marvell.com
+Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check")
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h  |  4 +-
+ drivers/scsi/qla2xxx/qla_init.c |  2 +
+ drivers/scsi/qla2xxx/qla_os.c   | 78 +++++++++++++++------------------
+ 3 files changed, 40 insertions(+), 44 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 2ea35e47ea44..0589ab8e6467 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -3759,6 +3759,7 @@ struct qla_qpair {
+       struct qla_fw_resources fwres ____cacheline_aligned;
+       u32     cmd_cnt;
+       u32     cmd_completion_cnt;
++      u32     prev_completion_cnt;
+ };
+ /* Place holder for FW buffer parameters */
+@@ -4618,6 +4619,7 @@ struct qla_hw_data {
+       struct qla_chip_state_84xx *cs84xx;
+       struct isp_operations *isp_ops;
+       struct workqueue_struct *wq;
++      struct work_struct heartbeat_work;
+       struct qlfc_fw fw_buf;
+       /* FCP_CMND priority support */
+@@ -4719,7 +4721,6 @@ struct qla_hw_data {
+       struct qla_hw_data_stat stat;
+       pci_error_state_t pci_error_state;
+-      u64 prev_cmd_cnt;
+       struct dma_pool *purex_dma_pool;
+       struct btree_head32 host_map;
+@@ -4865,7 +4866,6 @@ typedef struct scsi_qla_host {
+ #define SET_ZIO_THRESHOLD_NEEDED 32
+ #define ISP_ABORT_TO_ROM      33
+ #define VPORT_DELETE          34
+-#define HEARTBEAT_CHK         38
+ #define PROCESS_PUREX_IOCB    63
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index af8df5a800c6..c3ba2995209b 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -7096,12 +7096,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
+       ha->chip_reset++;
+       ha->base_qpair->chip_reset = ha->chip_reset;
+       ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0;
++      ha->base_qpair->prev_completion_cnt = 0;
+       for (i = 0; i < ha->max_qpairs; i++) {
+               if (ha->queue_pair_map[i]) {
+                       ha->queue_pair_map[i]->chip_reset =
+                               ha->base_qpair->chip_reset;
+                       ha->queue_pair_map[i]->cmd_cnt =
+                           ha->queue_pair_map[i]->cmd_completion_cnt = 0;
++                      ha->base_qpair->prev_completion_cnt = 0;
+               }
+       }
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index 77c0bf06f162..b224326bacee 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -2779,6 +2779,16 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+       return atomic_read(&vha->loop_state) == LOOP_READY;
+ }
++static void qla_heartbeat_work_fn(struct work_struct *work)
++{
++      struct qla_hw_data *ha = container_of(work,
++              struct qla_hw_data, heartbeat_work);
++      struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
++
++      if (!ha->flags.mbox_busy && base_vha->flags.init_done)
++              qla_no_op_mb(base_vha);
++}
++
+ static void qla2x00_iocb_work_fn(struct work_struct *work)
+ {
+       struct scsi_qla_host *vha = container_of(work,
+@@ -3217,6 +3227,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+           host->transportt, sht->vendor_id);
+       INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn);
++      INIT_WORK(&ha->heartbeat_work, qla_heartbeat_work_fn);
+       /* Set up the irqs */
+       ret = qla2x00_request_irqs(ha, rsp);
+@@ -7103,17 +7114,6 @@ qla2x00_do_dpc(void *data)
+                       qla2x00_lip_reset(base_vha);
+               }
+-              if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) {
+-                      /*
+-                       * if there is a mb in progress then that's
+-                       * enough of a check to see if fw is still ticking.
+-                       */
+-                      if (!ha->flags.mbox_busy && base_vha->flags.init_done)
+-                              qla_no_op_mb(base_vha);
+-
+-                      clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags);
+-              }
+-
+               ha->dpc_active = 0;
+ end_loop:
+               set_current_state(TASK_INTERRUPTIBLE);
+@@ -7172,57 +7172,51 @@ qla2x00_rst_aen(scsi_qla_host_t *vha)
+ static bool qla_do_heartbeat(struct scsi_qla_host *vha)
+ {
+-      u64 cmd_cnt, prev_cmd_cnt;
+-      bool do_hb = false;
+       struct qla_hw_data *ha = vha->hw;
+-      int i;
++      u32 cmpl_cnt;
++      u16 i;
++      bool do_heartbeat = false;
+-      /* if cmds are still pending down in fw, then do hb */
+-      if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) {
+-              do_hb = true;
++      /*
++       * Allow do_heartbeat only if we don’t have any active interrupts,
++       * but there are still IOs outstanding with firmware.
++       */
++      cmpl_cnt = ha->base_qpair->cmd_completion_cnt;
++      if (cmpl_cnt == ha->base_qpair->prev_completion_cnt &&
++          cmpl_cnt != ha->base_qpair->cmd_cnt) {
++              do_heartbeat = true;
+               goto skip;
+       }
++      ha->base_qpair->prev_completion_cnt = cmpl_cnt;
+       for (i = 0; i < ha->max_qpairs; i++) {
+-              if (ha->queue_pair_map[i] &&
+-                  ha->queue_pair_map[i]->cmd_cnt !=
+-                  ha->queue_pair_map[i]->cmd_completion_cnt) {
+-                      do_hb = true;
+-                      break;
++              if (ha->queue_pair_map[i]) {
++                      cmpl_cnt = ha->queue_pair_map[i]->cmd_completion_cnt;
++                      if (cmpl_cnt == ha->queue_pair_map[i]->prev_completion_cnt &&
++                          cmpl_cnt != ha->queue_pair_map[i]->cmd_cnt) {
++                              do_heartbeat = true;
++                              break;
++                      }
++                      ha->queue_pair_map[i]->prev_completion_cnt = cmpl_cnt;
+               }
+       }
+ skip:
+-      prev_cmd_cnt = ha->prev_cmd_cnt;
+-      cmd_cnt = ha->base_qpair->cmd_cnt;
+-      for (i = 0; i < ha->max_qpairs; i++) {
+-              if (ha->queue_pair_map[i])
+-                      cmd_cnt += ha->queue_pair_map[i]->cmd_cnt;
+-      }
+-      ha->prev_cmd_cnt = cmd_cnt;
+-
+-      if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50))
+-              /*
+-               * IOs are completing before periodic hb check.
+-               * IOs seems to be running, do hb for sanity check.
+-               */
+-              do_hb = true;
+-
+-      return do_hb;
++      return do_heartbeat;
+ }
+ static void qla_heart_beat(struct scsi_qla_host *vha)
+ {
++      struct qla_hw_data *ha = vha->hw;
++
+       if (vha->vp_idx)
+               return;
+       if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha))
+               return;
+-      if (qla_do_heartbeat(vha)) {
+-              set_bit(HEARTBEAT_CHK, &vha->dpc_flags);
+-              qla2xxx_wake_dpc(vha);
+-      }
++      if (qla_do_heartbeat(vha))
++              queue_work(ha->wq, &ha->heartbeat_work);
+ }
+ /**************************************************************************
+-- 
+2.35.1
+
diff --git a/queue-5.15/serial-8250_mtk-make-sure-to-select-the-right-featur.patch b/queue-5.15/serial-8250_mtk-make-sure-to-select-the-right-featur.patch
new file mode 100644 (file)
index 0000000..62ec8d5
--- /dev/null
@@ -0,0 +1,50 @@
+From e542f7f58f6a46e18587ecd4bfe0488c19596b25 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Apr 2022 15:23:27 +0200
+Subject: serial: 8250_mtk: Make sure to select the right FEATURE_SEL
+
+From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+[ Upstream commit 6f81fdded0d024c7d4084d434764f30bca1cd6b1 ]
+
+Set the FEATURE_SEL at probe time to make sure that BIT(0) is enabled:
+this guarantees that when the port is configured as AP UART, the
+right register layout is interpreted by the UART IP.
+
+Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20220427132328.228297-3-angelogioacchino.delregno@collabora.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/8250/8250_mtk.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
+index de48a58460f4..de57f47635cd 100644
+--- a/drivers/tty/serial/8250/8250_mtk.c
++++ b/drivers/tty/serial/8250/8250_mtk.c
+@@ -57,6 +57,9 @@
+ #define MTK_UART_XON1         40      /* I/O: Xon character 1 */
+ #define MTK_UART_XOFF1                42      /* I/O: Xoff character 1 */
++#define MTK_UART_FEATURE_SEL  39      /* Feature Selection register */
++#define MTK_UART_FEAT_NEWRMAP BIT(0)  /* Use new register map */
++
+ #ifdef CONFIG_SERIAL_8250_DMA
+ enum dma_rx_status {
+       DMA_RX_START = 0,
+@@ -572,6 +575,10 @@ static int mtk8250_probe(struct platform_device *pdev)
+               uart.dma = data->dma;
+ #endif
++      /* Set AP UART new register map */
++      writel(MTK_UART_FEAT_NEWRMAP, uart.port.membase +
++             (MTK_UART_FEATURE_SEL << uart.port.regshift));
++
+       /* Disable Rate Fix function */
+       writel(0x0, uart.port.membase +
+                       (MTK_UART_RATE_FIX << uart.port.regshift));
+-- 
+2.35.1
+
diff --git a/queue-5.15/serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch b/queue-5.15/serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch
new file mode 100644 (file)
index 0000000..d6dd94f
--- /dev/null
@@ -0,0 +1,48 @@
+From fbaa1f49ecb52375abe09e7f9259ff49d9483c40 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Mar 2022 19:00:42 +0800
+Subject: serial: sc16is7xx: Clear RS485 bits in the shutdown
+
+From: Hui Wang <hui.wang@canonical.com>
+
+[ Upstream commit 927728a34f11b5a27f4610bdb7068317d6fdc72a ]
+
+We tested RS485 function on an EVB which has SC16IS752, after
+finishing the test, we started the RS232 function test, but found the
+RTS is still working in the RS485 mode.
+
+That is because both startup and shutdown call port_update() to set
+the EFCR_REG, this will not clear the RS485 bits once the bits are set
+in the reconf_rs485(). To fix it, clear the RS485 bits in shutdown.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Hui Wang <hui.wang@canonical.com>
+Link: https://lore.kernel.org/r/20220308110042.108451-1-hui.wang@canonical.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/sc16is7xx.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
+index 0ab788058fa2..e98aa7b97cc5 100644
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -1055,10 +1055,12 @@ static void sc16is7xx_shutdown(struct uart_port *port)
+       /* Disable all interrupts */
+       sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
+-      /* Disable TX/RX */
++      /* Disable TX/RX, clear auto RS485 and RTS invert */
+       sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
+                             SC16IS7XX_EFCR_RXDISABLE_BIT |
+-                            SC16IS7XX_EFCR_TXDISABLE_BIT,
++                            SC16IS7XX_EFCR_TXDISABLE_BIT |
++                            SC16IS7XX_EFCR_AUTO_RS485_BIT |
++                            SC16IS7XX_EFCR_RTS_INVERT_BIT,
+                             SC16IS7XX_EFCR_RXDISABLE_BIT |
+                             SC16IS7XX_EFCR_TXDISABLE_BIT);
+-- 
+2.35.1
+
index 21f74d664cac1430e4f7cec9e08926dd6a919b28..b720e62ec0d8e03b216f3c530933c0638e219224 100644 (file)
@@ -17,3 +17,145 @@ usbnet-fix-memory-leak-in-error-case.patch
 net-rose-fix-uaf-bug-caused-by-rose_t0timer_expiry.patch
 netfilter-nft_set_pipapo-release-elements-in-clone-from-abort-path.patch
 netfilter-nf_tables-stricter-validation-of-element-data.patch
+btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch
+btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch
+btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch
+btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch
+input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch
+input-goodix-change-goodix_i2c_write-len-parameter-t.patch
+input-goodix-add-a-goodix.h-header-file.patch
+input-goodix-refactor-reset-handling.patch
+input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch
+dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch
+btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch
+drm-i915-disable-bonding-on-gen12-platforms.patch
+drm-i915-gt-register-the-migrate-contexts-with-their.patch
+drm-i915-replace-the-unconditional-clflush-with-drm_.patch
+pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch
+pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch
+media-ir_toy-prevent-device-from-hanging-during-tran.patch
+memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch
+ath11k-add-hw_param-for-wakeup_mhi.patch
+qed-improve-the-stack-space-of-filter_config.patch
+platform-x86-wmi-introduce-helper-to-convert-driver-.patch
+platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch
+platform-x86-wmi-fix-driver-notify-vs-probe-race.patch
+mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch
+mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch
+mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch
+bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch
+riscv-defconfig-enable-drm_nouveau.patch
+risc-v-defconfigs-set-config_fb-y-for-fb-console.patch
+net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch
+net-mlx5e-split-actions_match_supported-into-a-sub-f.patch
+net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch
+net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch
+asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch
+asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch
+asoc-rt5682-fix-deadlock-on-resume.patch
+netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch
+netfilter-nft_payload-support-for-inner-header-match.patch
+netfilter-nft_payload-don-t-allow-th-access-for-frag.patch
+drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch
+s390-boot-allocate-amode31-section-in-decompressor.patch
+s390-setup-use-physical-pointers-for-memblock_reserv.patch
+s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch
+ibmvnic-init-init_done_rc-earlier.patch
+ibmvnic-clear-fop-when-retrying-probe.patch
+ibmvnic-allow-queueing-resets-during-probe.patch
+virtio-blk-avoid-preallocating-big-sgl-for-data.patch
+io_uring-ensure-that-fsnotify-is-always-called.patch
+block-use-bdev_get_queue-in-bio.c.patch
+block-only-mark-bio-as-tracked-if-it-really-is-track.patch
+block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch
+stddef-introduce-struct_group-helper-macro.patch
+media-omap3isp-use-struct_group-for-memcpy-region.patch
+media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch
+mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch
+mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch
+cxl-port-hold-port-reference-until-decoder-release.patch
+clk-renesas-r9a07g044-update-multiplier-and-divider-.patch
+kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch
+kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch
+scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch
+scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch
+scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch
+scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch
+gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch
+vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch
+btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch
+btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch
+btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch
+btrfs-remove-device-item-and-update-super-block-in-t.patch
+drbd-add-error-handling-support-for-add_disk.patch
+drbd-fix-double-free-problem-in-drbd_create_device.patch
+drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch
+drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch
+drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch
+nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch
+nfsd-commit-operations-must-not-return-nfs-err_inval.patch
+riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch
+iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch
+batman-adv-use-netif_rx.patch
+mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch
+compiler-attributes-add-__alloc_size-for-better-boun.patch
+mm-vmalloc-introduce-array-allocation-functions.patch
+kvm-use-__vcalloc-for-very-large-allocations.patch
+btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch
+kvm-s390x-fix-sck-locking.patch
+scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch
+powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch
+powerpc-flexible-gpr-range-save-restore-macros.patch
+powerpc-tm-fix-more-userspace-r13-corruption.patch
+serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch
+bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch
+bus-mhi-fix-pm_state-conversion-to-string.patch
+stddef-introduce-declare_flex_array-helper.patch
+uapi-linux-stddef.h-add-include-guards.patch
+asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch
+asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch
+drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch
+kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch
+tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch
+tty-n_gsm-save-dlci-address-open-status-when-config-.patch
+tty-n_gsm-fix-frame-reception-handling.patch
+alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch
+alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch
+tty-n_gsm-fix-missing-update-of-modem-controls-after.patch
+btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch
+btrfs-zoned-use-dedicated-lock-for-data-relocation.patch
+kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch
+mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch
+mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch
+mm-memory-failure.c-fix-race-with-changing-page-comp.patch
+mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch
+tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch
+tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch
+powerpc-vdso-remove-cvdso_call_time-macro.patch
+powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch
+powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch
+serial-8250_mtk-make-sure-to-select-the-right-featur.patch
+tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch
+drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch
+drm-amdgpu-fix-rejecting-tahiti-gpus.patch
+drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch
+drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch
+drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch
+drm-i915-fix-a-race-between-vma-object-destruction-a.patch
+drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch
+drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch
+drm-mediatek-detect-cmdq-execution-timeout.patch
+drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch
+drm-mediatek-add-vblank-register-unregister-callback.patch
+drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch
+drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch
+drm-msm-properly-add-and-remove-internal-bridges.patch
+bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch
+bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch
+io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch
+irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch
+rxrpc-fix-locking-issue.patch
+dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch
+dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch
+module-change-to-print-useful-messages-from-elf_vali.patch
+module-fix-e_shstrndx-.sh_size-0-oob-access.patch
diff --git a/queue-5.15/stddef-introduce-declare_flex_array-helper.patch b/queue-5.15/stddef-introduce-declare_flex_array-helper.patch
new file mode 100644 (file)
index 0000000..ed58091
--- /dev/null
@@ -0,0 +1,155 @@
+From f387f204fd79d9ddb2e48d62eb9aa8d94da222e6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Aug 2021 11:21:23 -0700
+Subject: stddef: Introduce DECLARE_FLEX_ARRAY() helper
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit 3080ea5553cc909b000d1f1d964a9041962f2c5b ]
+
+There are many places where kernel code wants to have several different
+typed trailing flexible arrays. This would normally be done with multiple
+flexible arrays in a union, but since GCC and Clang don't (on the surface)
+allow this, there have been many open-coded workarounds, usually involving
+neighboring 0-element arrays at the end of a structure. For example,
+instead of something like this:
+
+struct thing {
+       ...
+       union {
+               struct type1 foo[];
+               struct type2 bar[];
+       };
+};
+
+code works around the compiler with:
+
+struct thing {
+       ...
+       struct type1 foo[0];
+       struct type2 bar[];
+};
+
+Another case is when a flexible array is wanted as the single member
+within a struct (which itself is usually in a union). For example, this
+would be worked around as:
+
+union many {
+       ...
+       struct {
+               struct type3 baz[0];
+       };
+};
+
+These kinds of work-arounds cause problems with size checks against such
+zero-element arrays (for example when building with -Warray-bounds and
+-Wzero-length-bounds, and with the coming FORTIFY_SOURCE improvements),
+so they must all be converted to "real" flexible arrays, avoiding warnings
+like this:
+
+fs/hpfs/anode.c: In function 'hpfs_add_sector_to_btree':
+fs/hpfs/anode.c:209:27: warning: array subscript 0 is outside the bounds of an interior zero-length array 'struct bplus_internal_node[0]' [-Wzero-length-bounds]
+  209 |    anode->btree.u.internal[0].down = cpu_to_le32(a);
+      |    ~~~~~~~~~~~~~~~~~~~~~~~^~~
+In file included from fs/hpfs/hpfs_fn.h:26,
+                 from fs/hpfs/anode.c:10:
+fs/hpfs/hpfs.h:412:32: note: while referencing 'internal'
+  412 |     struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving
+      |                                ^~~~~~~~
+
+drivers/net/can/usb/etas_es58x/es58x_fd.c: In function 'es58x_fd_tx_can_msg':
+drivers/net/can/usb/etas_es58x/es58x_fd.c:360:35: warning: array subscript 65535 is outside the bounds of an interior zero-length array 'u8[0]' {aka 'unsigned char[]'} [-Wzero-length-bounds]
+  360 |  tx_can_msg = (typeof(tx_can_msg))&es58x_fd_urb_cmd->raw_msg[msg_len];
+      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In file included from drivers/net/can/usb/etas_es58x/es58x_core.h:22,
+                 from drivers/net/can/usb/etas_es58x/es58x_fd.c:17:
+drivers/net/can/usb/etas_es58x/es58x_fd.h:231:6: note: while referencing 'raw_msg'
+  231 |   u8 raw_msg[0];
+      |      ^~~~~~~
+
+However, it _is_ entirely possible to have one or more flexible arrays
+in a struct or union: it just has to be in another struct. And since it
+cannot be alone in a struct, such a struct must have at least 1 other
+named member -- but that member can be zero sized. Wrap all this nonsense
+into the new DECLARE_FLEX_ARRAY() in support of having flexible arrays
+in unions (or alone in a struct).
+
+As with struct_group(), since this is needed in UAPI headers as well,
+implement the core there, with a non-UAPI wrapper.
+
+Additionally update kernel-doc to understand its existence.
+
+https://github.com/KSPP/linux/issues/137
+
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/stddef.h      | 13 +++++++++++++
+ include/uapi/linux/stddef.h | 16 ++++++++++++++++
+ scripts/kernel-doc          |  2 ++
+ 3 files changed, 31 insertions(+)
+
+diff --git a/include/linux/stddef.h b/include/linux/stddef.h
+index 938216f8ab7e..31fdbb784c24 100644
+--- a/include/linux/stddef.h
++++ b/include/linux/stddef.h
+@@ -84,4 +84,17 @@ enum {
+ #define struct_group_tagged(TAG, NAME, MEMBERS...) \
+       __struct_group(TAG, NAME, /* no attrs */, MEMBERS)
++/**
++ * DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
++ *
++ * @TYPE: The type of each flexible array element
++ * @NAME: The name of the flexible array member
++ *
++ * In order to have a flexible array member in a union or alone in a
++ * struct, it needs to be wrapped in an anonymous struct with at least 1
++ * named member, but that member can be empty.
++ */
++#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
++      __DECLARE_FLEX_ARRAY(TYPE, NAME)
++
+ #endif
+diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h
+index 610204f7c275..3021ea25a284 100644
+--- a/include/uapi/linux/stddef.h
++++ b/include/uapi/linux/stddef.h
+@@ -25,3 +25,19 @@
+               struct { MEMBERS } ATTRS; \
+               struct TAG { MEMBERS } ATTRS NAME; \
+       }
++
++/**
++ * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
++ *
++ * @TYPE: The type of each flexible array element
++ * @NAME: The name of the flexible array member
++ *
++ * In order to have a flexible array member in a union or alone in a
++ * struct, it needs to be wrapped in an anonymous struct with at least 1
++ * named member, but that member can be empty.
++ */
++#define __DECLARE_FLEX_ARRAY(TYPE, NAME)      \
++      struct { \
++              struct { } __empty_ ## NAME; \
++              TYPE NAME[]; \
++      }
+diff --git a/scripts/kernel-doc b/scripts/kernel-doc
+index 38aa799a776c..5d54b57ff90c 100755
+--- a/scripts/kernel-doc
++++ b/scripts/kernel-doc
+@@ -1263,6 +1263,8 @@ sub dump_struct($$) {
+       $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos;
+       # replace DECLARE_KFIFO_PTR
+       $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos;
++      # replace DECLARE_FLEX_ARRAY
++      $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos;
+       my $declaration = $members;
+       # Split nested struct/union elements as newer ones
+-- 
+2.35.1
+
diff --git a/queue-5.15/stddef-introduce-struct_group-helper-macro.patch b/queue-5.15/stddef-introduce-struct_group-helper-macro.patch
new file mode 100644 (file)
index 0000000..9a57509
--- /dev/null
@@ -0,0 +1,261 @@
+From 553ceca024d425f94b68e9a132423f8eb3fb7081 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 May 2021 20:01:15 -0700
+Subject: stddef: Introduce struct_group() helper macro
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit 50d7bd38c3aafc4749e05e8d7fcb616979143602 ]
+
+Kernel code has a regular need to describe groups of members within a
+structure usually when they need to be copied or initialized separately
+from the rest of the surrounding structure. The generally accepted design
+pattern in C is to use a named sub-struct:
+
+       struct foo {
+               int one;
+               struct {
+                       int two;
+                       int three, four;
+               } thing;
+               int five;
+       };
+
+This would allow for traditional references and sizing:
+
+       memcpy(&dst.thing, &src.thing, sizeof(dst.thing));
+
+However, doing this would mean that referencing struct members enclosed
+by such named structs would always require including the sub-struct name
+in identifiers:
+
+       do_something(dst.thing.three);
+
+This has tended to be quite inflexible, especially when such groupings
+need to be added to established code which causes huge naming churn.
+Three workarounds exist in the kernel for this problem, and each have
+other negative properties.
+
+To avoid the naming churn, there is a design pattern of adding macro
+aliases for the named struct:
+
+       #define f_three thing.three
+
+This ends up polluting the global namespace, and makes it difficult to
+search for identifiers.
+
+Another common work-around in kernel code avoids the pollution by avoiding
+the named struct entirely, instead identifying the group's boundaries using
+either a pair of empty anonymous structs of a pair of zero-element arrays:
+
+       struct foo {
+               int one;
+               struct { } start;
+               int two;
+               int three, four;
+               struct { } finish;
+               int five;
+       };
+
+       struct foo {
+               int one;
+               int start[0];
+               int two;
+               int three, four;
+               int finish[0];
+               int five;
+       };
+
+This allows code to avoid needing to use a sub-struct named for member
+references within the surrounding structure, but loses the benefits of
+being able to actually use such a struct, making it rather fragile. Using
+these requires open-coded calculation of sizes and offsets. The efforts
+made to avoid common mistakes include lots of comments, or adding various
+BUILD_BUG_ON()s. Such code is left with no way for the compiler to reason
+about the boundaries (e.g. the "start" object looks like it's 0 bytes
+in length), making bounds checking depend on open-coded calculations:
+
+       if (length > offsetof(struct foo, finish) -
+                    offsetof(struct foo, start))
+               return -EINVAL;
+       memcpy(&dst.start, &src.start, offsetof(struct foo, finish) -
+                                      offsetof(struct foo, start));
+
+However, the vast majority of places in the kernel that operate on
+groups of members do so without any identification of the grouping,
+relying either on comments or implicit knowledge of the struct contents,
+which is even harder for the compiler to reason about, and results in
+even more fragile manual sizing, usually depending on member locations
+outside of the region (e.g. to copy "two" and "three", use the start of
+"four" to find the size):
+
+       BUILD_BUG_ON((offsetof(struct foo, four) <
+                     offsetof(struct foo, two)) ||
+                    (offsetof(struct foo, four) <
+                     offsetof(struct foo, three));
+       if (length > offsetof(struct foo, four) -
+                    offsetof(struct foo, two))
+               return -EINVAL;
+       memcpy(&dst.two, &src.two, length);
+
+In order to have a regular programmatic way to describe a struct
+region that can be used for references and sizing, can be examined for
+bounds checking, avoids forcing the use of intermediate identifiers,
+and avoids polluting the global namespace, introduce the struct_group()
+macro. This macro wraps the member declarations to create an anonymous
+union of an anonymous struct (no intermediate name) and a named struct
+(for references and sizing):
+
+       struct foo {
+               int one;
+               struct_group(thing,
+                       int two;
+                       int three, four;
+               );
+               int five;
+       };
+
+       if (length > sizeof(src.thing))
+               return -EINVAL;
+       memcpy(&dst.thing, &src.thing, length);
+       do_something(dst.three);
+
+There are some rare cases where the resulting struct_group() needs
+attributes added, so struct_group_attr() is also introduced to allow
+for specifying struct attributes (e.g. __align(x) or __packed).
+Additionally, there are places where such declarations would like to
+have the struct be tagged, so struct_group_tagged() is added.
+
+Given there is a need for a handful of UAPI uses too, the underlying
+__struct_group() macro has been defined in UAPI so it can be used there
+too.
+
+To avoid confusing scripts/kernel-doc, hide the macro from its struct
+parsing.
+
+Co-developed-by: Keith Packard <keithp@keithp.com>
+Signed-off-by: Keith Packard <keithp@keithp.com>
+Acked-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Link: https://lore.kernel.org/lkml/20210728023217.GC35706@embeddedor
+Enhanced-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Link: https://lore.kernel.org/lkml/41183a98-bdb9-4ad6-7eab-5a7292a6df84@rasmusvillemoes.dk
+Enhanced-by: Dan Williams <dan.j.williams@intel.com>
+Link: https://lore.kernel.org/lkml/1d9a2e6df2a9a35b2cdd50a9a68cac5991e7e5f0.camel@intel.com
+Enhanced-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Link: https://lore.kernel.org/lkml/YQKa76A6XuFqgM03@phenom.ffwll.local
+Acked-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/stddef.h      | 48 +++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/stddef.h | 21 ++++++++++++++++
+ scripts/kernel-doc          |  7 ++++++
+ 3 files changed, 76 insertions(+)
+
+diff --git a/include/linux/stddef.h b/include/linux/stddef.h
+index 998a4ba28eba..938216f8ab7e 100644
+--- a/include/linux/stddef.h
++++ b/include/linux/stddef.h
+@@ -36,4 +36,52 @@ enum {
+ #define offsetofend(TYPE, MEMBER) \
+       (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
++/**
++ * struct_group() - Wrap a set of declarations in a mirrored struct
++ *
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical
++ * layout and size: one anonymous and one named. The former can be
++ * used normally without sub-struct naming, and the latter can be
++ * used to reason about the start, end, and size of the group of
++ * struct members.
++ */
++#define struct_group(NAME, MEMBERS...)        \
++      __struct_group(/* no tag */, NAME, /* no attrs */, MEMBERS)
++
++/**
++ * struct_group_attr() - Create a struct_group() with trailing attributes
++ *
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @ATTRS: Any struct attributes to apply
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical
++ * layout and size: one anonymous and one named. The former can be
++ * used normally without sub-struct naming, and the latter can be
++ * used to reason about the start, end, and size of the group of
++ * struct members. Includes structure attributes argument.
++ */
++#define struct_group_attr(NAME, ATTRS, MEMBERS...) \
++      __struct_group(/* no tag */, NAME, ATTRS, MEMBERS)
++
++/**
++ * struct_group_tagged() - Create a struct_group with a reusable tag
++ *
++ * @TAG: The tag name for the named sub-struct
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical
++ * layout and size: one anonymous and one named. The former can be
++ * used normally without sub-struct naming, and the latter can be
++ * used to reason about the start, end, and size of the group of
++ * struct members. Includes struct tag argument for the named copy,
++ * so the specified layout can be reused later.
++ */
++#define struct_group_tagged(TAG, NAME, MEMBERS...) \
++      __struct_group(TAG, NAME, /* no attrs */, MEMBERS)
++
+ #endif
+diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h
+index ee8220f8dcf5..610204f7c275 100644
+--- a/include/uapi/linux/stddef.h
++++ b/include/uapi/linux/stddef.h
+@@ -4,3 +4,24 @@
+ #ifndef __always_inline
+ #define __always_inline inline
+ #endif
++
++/**
++ * __struct_group() - Create a mirrored named and anonyomous struct
++ *
++ * @TAG: The tag name for the named sub-struct (usually empty)
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @ATTRS: Any struct attributes (usually empty)
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical layout
++ * and size: one anonymous and one named. The former's members can be used
++ * normally without sub-struct naming, and the latter can be used to
++ * reason about the start, end, and size of the group of struct members.
++ * The named struct can also be explicitly tagged for layer reuse, as well
++ * as both having struct attributes appended.
++ */
++#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
++      union { \
++              struct { MEMBERS } ATTRS; \
++              struct TAG { MEMBERS } ATTRS NAME; \
++      }
+diff --git a/scripts/kernel-doc b/scripts/kernel-doc
+index cfcb60737957..38aa799a776c 100755
+--- a/scripts/kernel-doc
++++ b/scripts/kernel-doc
+@@ -1245,6 +1245,13 @@ sub dump_struct($$) {
+       $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
+       $members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
+       $members =~ s/\s*____cacheline_aligned/ /gos;
++      # unwrap struct_group():
++      # - first eat non-declaration parameters and rewrite for final match
++      # - then remove macro, outer parens, and trailing semicolon
++      $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos;
++      $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos;
++      $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos;
++      $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos;
+       my $args = qr{([^,)]+)};
+       # replace DECLARE_BITMAP
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-fix-frame-reception-handling.patch b/queue-5.15/tty-n_gsm-fix-frame-reception-handling.patch
new file mode 100644 (file)
index 0000000..2e39cd1
--- /dev/null
@@ -0,0 +1,123 @@
+From 7409b51bf34ae44c47a07b1531c801b5ba167121 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Apr 2022 02:42:11 -0700
+Subject: tty: n_gsm: fix frame reception handling
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+[ Upstream commit 7a0e4b1733b635026a87c023f6d703faf0095e39 ]
+
+The frame checksum (FCS) is currently handled in gsm_queue() after
+reception of a frame. However, this breaks layering. A workaround with
+'received_fcs' was implemented so far.
+Furthermore, frames are handled as such even if no end flag was received.
+Move FCS calculation from gsm_queue() to gsm0_receive() and gsm1_receive().
+Also delay gsm_queue() call there until a full frame was received to fix
+both points.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220414094225.4527-6-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 53 +++++++++++++++++++++++++--------------------
+ 1 file changed, 30 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index 3038e5631be5..d3d5308daf35 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -221,7 +221,6 @@ struct gsm_mux {
+       int encoding;
+       u8 control;
+       u8 fcs;
+-      u8 received_fcs;
+       u8 *txframe;                    /* TX framing buffer */
+       /* Method for the receiver side */
+@@ -1799,18 +1798,7 @@ static void gsm_queue(struct gsm_mux *gsm)
+       u8 cr;
+       int address;
+       int i, j, k, address_tmp;
+-      /* We have to sneak a look at the packet body to do the FCS.
+-         A somewhat layering violation in the spec */
+-      if ((gsm->control & ~PF) == UI)
+-              gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+-      if (gsm->encoding == 0) {
+-              /* WARNING: gsm->received_fcs is used for
+-              gsm->encoding = 0 only.
+-              In this case it contain the last piece of data
+-              required to generate final CRC */
+-              gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
+-      }
+       if (gsm->fcs != GOOD_FCS) {
+               gsm->bad_fcs++;
+               if (debug & 4)
+@@ -1997,19 +1985,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
+               break;
+       case GSM_DATA:          /* Data */
+               gsm->buf[gsm->count++] = c;
+-              if (gsm->count == gsm->len)
++              if (gsm->count == gsm->len) {
++                      /* Calculate final FCS for UI frames over all data */
++                      if ((gsm->control & ~PF) != UIH) {
++                              gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
++                                                           gsm->count);
++                      }
+                       gsm->state = GSM_FCS;
++              }
+               break;
+       case GSM_FCS:           /* FCS follows the packet */
+-              gsm->received_fcs = c;
+-              gsm_queue(gsm);
++              gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->state = GSM_SSOF;
+               break;
+       case GSM_SSOF:
+-              if (c == GSM0_SOF) {
+-                      gsm->state = GSM_SEARCH;
+-                      break;
+-              }
++              gsm->state = GSM_SEARCH;
++              if (c == GSM0_SOF)
++                      gsm_queue(gsm);
++              else
++                      gsm->bad_size++;
+               break;
+       default:
+               pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
+@@ -2038,11 +2032,24 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+               return;
+       }
+       if (c == GSM1_SOF) {
+-              /* EOF is only valid in frame if we have got to the data state
+-                 and received at least one byte (the FCS) */
+-              if (gsm->state == GSM_DATA && gsm->count) {
+-                      /* Extract the FCS */
++              /* EOF is only valid in frame if we have got to the data state */
++              if (gsm->state == GSM_DATA) {
++                      if (gsm->count < 1) {
++                              /* Missing FSC */
++                              gsm->malformed++;
++                              gsm->state = GSM_START;
++                              return;
++                      }
++                      /* Remove the FCS from data */
+                       gsm->count--;
++                      if ((gsm->control & ~PF) != UIH) {
++                              /* Calculate final FCS for UI frames over all
++                               * data but FCS
++                               */
++                              gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
++                                                           gsm->count);
++                      }
++                      /* Add the FCS itself to test against GOOD_FCS */
+                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+                       gsm->len = gsm->count;
+                       gsm_queue(gsm);
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch b/queue-5.15/tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch
new file mode 100644 (file)
index 0000000..5d58fd6
--- /dev/null
@@ -0,0 +1,70 @@
+From ac5b2e58dfe6e9c75456f9f1d3671c55137d4162 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 May 2022 10:17:33 +0200
+Subject: tty: n_gsm: fix invalid gsmtty_write_room() result
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+[ Upstream commit 9361ebfbb79fd1bc8594a487c01ad52cdaa391ea ]
+
+gsmtty_write() does not prevent the user to use the full fifo size of 4096
+bytes as allocated in gsm_dlci_alloc(). However, gsmtty_write_room() tries
+to limit the return value by 'TX_SIZE' and returns a negative value if the
+fifo has more than 'TX_SIZE' bytes stored. This is obviously wrong as
+'TX_SIZE' is defined as 512.
+Define 'TX_SIZE' to the fifo size and use it accordingly for allocation to
+keep the current behavior. Return the correct remaining size of the fifo in
+gsmtty_write_room() via kfifo_avail().
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220504081733.3494-3-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index fd4a86111a6e..4a430f6ca170 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -137,6 +137,7 @@ struct gsm_dlci {
+       int retries;
+       /* Uplink tty if active */
+       struct tty_port port;   /* The tty bound to this DLCI if there is one */
++#define TX_SIZE               4096    /* Must be power of 2. */
+       struct kfifo fifo;      /* Queue fifo for the DLCI */
+       int adaption;           /* Adaption layer in use */
+       int prev_adaption;
+@@ -1758,7 +1759,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
+               return NULL;
+       spin_lock_init(&dlci->lock);
+       mutex_init(&dlci->mutex);
+-      if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) {
++      if (kfifo_alloc(&dlci->fifo, TX_SIZE, GFP_KERNEL) < 0) {
+               kfree(dlci);
+               return NULL;
+       }
+@@ -3035,8 +3036,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
+  *    Virtual tty side
+  */
+-#define TX_SIZE               512
+-
+ /**
+  *    gsm_modem_upd_via_data  -       send modem bits via convergence layer
+  *    @dlci: channel
+@@ -3274,7 +3273,7 @@ static unsigned int gsmtty_write_room(struct tty_struct *tty)
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (dlci->state == DLCI_CLOSED)
+               return 0;
+-      return TX_SIZE - kfifo_len(&dlci->fifo);
++      return kfifo_avail(&dlci->fifo);
+ }
+ static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch b/queue-5.15/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch
new file mode 100644 (file)
index 0000000..ab89390
--- /dev/null
@@ -0,0 +1,244 @@
+From 95fe37f5383e99f2e764fa8b3fae1a9a59714626 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Apr 2022 00:10:24 -0700
+Subject: tty: n_gsm: fix invalid use of MSC in advanced option
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+[ Upstream commit c19ffe00fed6bb423d81406d2a7e5793074c7d83 ]
+
+n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010.
+See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516
+The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to
+the newer 27.010 here. Chapter 5.4.6.3.7 states that the Modem Status
+Command (MSC) shall only be used if the basic option was chosen.
+The current implementation uses MSC frames even if advanced option was
+chosen to inform the peer about modem line state updates. A standard
+conform peer may choose to discard these frames in advanced option mode.
+Furthermore, gsmtty_modem_update() is not part of the 'tty_operations'
+functions despite its name.
+Rename gsmtty_modem_update() to gsm_modem_update() to clarify this. Split
+its function into gsm_modem_upd_via_data() and gsm_modem_upd_via_msc()
+depending on the encoding and adaption. Introduce gsm_dlci_modem_output()
+as adaption of gsm_dlci_data_output() to encode and queue empty frames in
+advanced option mode. Use it in gsm_modem_upd_via_data().
+gsm_modem_upd_via_msc() is based on the initial gsmtty_modem_update()
+function which used only MSC frames to update modem states.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220422071025.5490-2-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 125 +++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 117 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index c52d5e0d5c6f..c8ca00fad8e4 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -371,7 +371,7 @@ static const u8 gsm_fcs8[256] = {
+ #define GOOD_FCS      0xCF
+ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
+-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk);
++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
+ /**
+  *    gsm_fcs_add     -       update FCS
+@@ -928,6 +928,63 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
+       return size;
+ }
++/**
++ *    gsm_dlci_modem_output   -       try and push modem status out of a DLCI
++ *    @gsm: mux
++ *    @dlci: the DLCI to pull modem status from
++ *    @brk: break signal
++ *
++ *    Push an empty frame in to the transmit queue to update the modem status
++ *    bits and to transmit an optional break.
++ *
++ *    Caller must hold the tx_lock of the mux.
++ */
++
++static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
++                               u8 brk)
++{
++      u8 *dp = NULL;
++      struct gsm_msg *msg;
++      int size;
++
++      /* for modem bits without break data */
++      if (dlci->adaption == 1) {
++              size = 0;
++      } else if (dlci->adaption == 2) {
++              size = 1;
++              if (brk > 0)
++                      size++;
++      } else {
++              pr_err("%s: unsupported adaption %d\n", __func__,
++                     dlci->adaption);
++      }
++
++      msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
++      if (!msg) {
++              pr_err("%s: gsm_data_alloc error", __func__);
++              return -ENOMEM;
++      }
++      dp = msg->data;
++      switch (dlci->adaption) {
++      case 1: /* Unstructured */
++              break;
++      case 2: /* Unstructured with modem bits. */
++              if (brk == 0) {
++                      *dp++ = (gsm_encode_modem(dlci) << 1) | EA;
++              } else {
++                      *dp++ = gsm_encode_modem(dlci) << 1;
++                      *dp++ = (brk << 4) | 2 | EA; /* Length, Break, EA */
++              }
++              break;
++      default:
++              /* Handled above */
++              break;
++      }
++
++      __gsm_data_queue(dlci, msg);
++      return size;
++}
++
+ /**
+  *    gsm_dlci_data_sweep             -       look for data to send
+  *    @gsm: the GSM mux
+@@ -1492,7 +1549,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
+               pr_debug("DLCI %d goes open.\n", dlci->addr);
+       /* Send current modem state */
+       if (dlci->addr)
+-              gsmtty_modem_update(dlci, 0);
++              gsm_modem_update(dlci, 0);
+       wake_up(&dlci->gsm->event);
+ }
+@@ -2977,12 +3034,43 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
+ #define TX_SIZE               512
+-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
++/**
++ *    gsm_modem_upd_via_data  -       send modem bits via convergence layer
++ *    @dlci: channel
++ *    @brk: break signal
++ *
++ *    Send an empty frame to signal mobile state changes and to transmit the
++ *    break signal for adaption 2.
++ */
++
++static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
++{
++      struct gsm_mux *gsm = dlci->gsm;
++      unsigned long flags;
++
++      if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
++              return;
++
++      spin_lock_irqsave(&gsm->tx_lock, flags);
++      gsm_dlci_modem_output(gsm, dlci, brk);
++      spin_unlock_irqrestore(&gsm->tx_lock, flags);
++}
++
++/**
++ *    gsm_modem_upd_via_msc   -       send modem bits via control frame
++ *    @dlci: channel
++ *    @brk: break signal
++ */
++
++static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
+ {
+       u8 modembits[3];
+       struct gsm_control *ctrl;
+       int len = 2;
++      if (dlci->gsm->encoding != 0)
++              return 0;
++
+       modembits[0] = (dlci->addr << 2) | 2 | EA;  /* DLCI, Valid, EA */
+       if (!brk) {
+               modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
+@@ -2997,6 +3085,27 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
+       return gsm_control_wait(dlci->gsm, ctrl);
+ }
++/**
++ *    gsm_modem_update        -       send modem status line state
++ *    @dlci: channel
++ *    @brk: break signal
++ */
++
++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
++{
++      if (dlci->adaption == 2) {
++              /* Send convergence layer type 2 empty data frame. */
++              gsm_modem_upd_via_data(dlci, brk);
++              return 0;
++      } else if (dlci->gsm->encoding == 0) {
++              /* Send as MSC control message. */
++              return gsm_modem_upd_via_msc(dlci, brk);
++      }
++
++      /* Modem status lines are not supported. */
++      return -EPROTONOSUPPORT;
++}
++
+ static int gsm_carrier_raised(struct tty_port *port)
+ {
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+@@ -3029,7 +3138,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff)
+               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+-              gsmtty_modem_update(dlci, 0);
++              gsm_modem_update(dlci, 0);
+       }
+ }
+@@ -3218,7 +3327,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+-              return gsmtty_modem_update(dlci, 0);
++              return gsm_modem_update(dlci, 0);
+       }
+       return 0;
+ }
+@@ -3279,7 +3388,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
+               dlci->modem_tx &= ~TIOCM_RTS;
+       dlci->throttled = true;
+       /* Send an MSC with RTS cleared */
+-      gsmtty_modem_update(dlci, 0);
++      gsm_modem_update(dlci, 0);
+ }
+ static void gsmtty_unthrottle(struct tty_struct *tty)
+@@ -3291,7 +3400,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
+               dlci->modem_tx |= TIOCM_RTS;
+       dlci->throttled = false;
+       /* Send an MSC with RTS set */
+-      gsmtty_modem_update(dlci, 0);
++      gsm_modem_update(dlci, 0);
+ }
+ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+@@ -3309,7 +3418,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+               if (encode > 0x0F)
+                       encode = 0x0F;  /* Best effort */
+       }
+-      return gsmtty_modem_update(dlci, encode);
++      return gsm_modem_update(dlci, encode);
+ }
+ static void gsmtty_cleanup(struct tty_struct *tty)
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-fix-missing-update-of-modem-controls-after.patch b/queue-5.15/tty-n_gsm-fix-missing-update-of-modem-controls-after.patch
new file mode 100644 (file)
index 0000000..ee7b7e3
--- /dev/null
@@ -0,0 +1,48 @@
+From 89a62581ea1dbac20493de0e2927609322683feb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 20 Apr 2022 03:13:44 -0700
+Subject: tty: n_gsm: fix missing update of modem controls after DLCI open
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+[ Upstream commit 48473802506d2d6151f59e0e764932b33b53cb3b ]
+
+Currently the peer is not informed about the initial state of the modem
+control lines after a new DLCI has been opened.
+Fix this by sending the initial modem control line states after DLCI open.
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220420101346.3315-1-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index d3d5308daf35..c52d5e0d5c6f 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -371,6 +371,7 @@ static const u8 gsm_fcs8[256] = {
+ #define GOOD_FCS      0xCF
+ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
++static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk);
+ /**
+  *    gsm_fcs_add     -       update FCS
+@@ -1489,6 +1490,9 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
+       dlci->state = DLCI_OPEN;
+       if (debug & 8)
+               pr_debug("DLCI %d goes open.\n", dlci->addr);
++      /* Send current modem state */
++      if (dlci->addr)
++              gsmtty_modem_update(dlci, 0);
+       wake_up(&dlci->gsm->event);
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch b/queue-5.15/tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch
new file mode 100644 (file)
index 0000000..b34fb67
--- /dev/null
@@ -0,0 +1,62 @@
+From e85282d8f21109436a793e2b711aba30b2fabd1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Apr 2022 03:47:26 -0700
+Subject: tty: n_gsm: fix sometimes uninitialized warning in
+ gsm_dlci_modem_output()
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+[ Upstream commit 19317433057dc1f2ca9a975e4e6b547282c2a5ef ]
+
+'size' may be used uninitialized in gsm_dlci_modem_output() if called with
+an adaption that is neither 1 nor 2. The function is currently only called
+by gsm_modem_upd_via_data() and only for adaption 2.
+Properly handle every invalid case by returning -EINVAL to silence the
+compiler warning and avoid future regressions.
+
+Fixes: c19ffe00fed6 ("tty: n_gsm: fix invalid use of MSC in advanced option")
+Cc: stable@vger.kernel.org
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20220425104726.7986-1-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index c8ca00fad8e4..fd4a86111a6e 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -945,18 +945,21 @@ static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
+ {
+       u8 *dp = NULL;
+       struct gsm_msg *msg;
+-      int size;
++      int size = 0;
+       /* for modem bits without break data */
+-      if (dlci->adaption == 1) {
+-              size = 0;
+-      } else if (dlci->adaption == 2) {
+-              size = 1;
++      switch (dlci->adaption) {
++      case 1: /* Unstructured */
++              break;
++      case 2: /* Unstructured with modem bits. */
++              size++;
+               if (brk > 0)
+                       size++;
+-      } else {
++              break;
++      default:
+               pr_err("%s: unsupported adaption %d\n", __func__,
+                      dlci->adaption);
++              return -EINVAL;
+       }
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch b/queue-5.15/tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch
new file mode 100644 (file)
index 0000000..4b5db5e
--- /dev/null
@@ -0,0 +1,83 @@
+From 2b325213c8a48eab25b91459eabb9e4ad3339b65 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Aug 2021 20:17:47 +0800
+Subject: tty: n_gsm: Modify CR,PF bit when config requester
+
+From: Zhenguo Zhao <Zhenguo.Zhao1@unisoc.com>
+
+[ Upstream commit cc0f42122a7e7a5ede9c5f2a41199128b8449eda ]
+
+When n_gsm config "initiator=0",as requester,gsmld receives dlci SABM/DISC
+control command frame,but send UA frame is error.
+
+Example:
+Gsmld receive dlc0 SABM frame "f9 03 3f 01 1c f9",now it sends UA
+frame "f9 01 63 01 a3 f9",CR and PF bit are 0,but it should be set
+1 from requster to initiator.
+
+Kernel test log as follows:
+
+Before modify
+
+[  271.732031] c1 gsmld_receive: 00000000: f9 03 3f 01 1c f9
+[  271.741719] c1 <-- 0) C: SABM(P)
+[  271.749483] c1 gsmld_output: 00000000: f9 01 63 01 a3 f9
+[  271.758337] c1 --> 0) R: UA(F)
+
+After modify
+
+[  261.233188] c0 gsmld_receive: 00000000: f9 03 3f 01 1c f9
+[  261.242767] c0 <-- 0) C: SABM(P)
+[  261.250497] c0 gsmld_output: 00000000: f9 03 73 01 d7 f9
+[  261.259759] c0 --> 0) C: UA(P)
+
+Signed-off-by: Zhenguo Zhao <Zhenguo.Zhao1@unisoc.com>
+Link: https://lore.kernel.org/r/1629461872-26965-3-git-send-email-zhenguo6858@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index 6734ef22c304..91ce8e6e889a 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -625,7 +625,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
+ static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
+ {
+-      gsm_send(gsm, addr, 0, control);
++      gsm_send(gsm, addr, 1, control);
+ }
+ /**
+@@ -1818,9 +1818,9 @@ static void gsm_queue(struct gsm_mux *gsm)
+               if (dlci == NULL)
+                       return;
+               if (dlci->dead)
+-                      gsm_response(gsm, address, DM);
++                      gsm_response(gsm, address, DM|PF);
+               else {
+-                      gsm_response(gsm, address, UA);
++                      gsm_response(gsm, address, UA|PF);
+                       gsm_dlci_open(dlci);
+               }
+               break;
+@@ -1828,11 +1828,11 @@ static void gsm_queue(struct gsm_mux *gsm)
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
+-                      gsm_response(gsm, address, DM);
++                      gsm_response(gsm, address, DM|PF);
+                       return;
+               }
+               /* Real close complete */
+-              gsm_response(gsm, address, UA);
++              gsm_response(gsm, address, UA|PF);
+               gsm_dlci_close(dlci);
+               break;
+       case UA|PF:
+-- 
+2.35.1
+
diff --git a/queue-5.15/tty-n_gsm-save-dlci-address-open-status-when-config-.patch b/queue-5.15/tty-n_gsm-save-dlci-address-open-status-when-config-.patch
new file mode 100644 (file)
index 0000000..afc84f9
--- /dev/null
@@ -0,0 +1,134 @@
+From 6bbfd936ed4e7116ec27460069c010d11314a45e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Aug 2021 20:17:52 +0800
+Subject: tty: n_gsm: Save dlci address open status when config requester
+
+From: Zhenguo Zhao <Zhenguo.Zhao1@unisoc.com>
+
+[ Upstream commit 0b91b5332368f2fb0c3e5cfebc6aff9e167acd8b ]
+
+When n_gsm config "initiator=0",as requester ,receive SABM frame,n_gsm
+register gsmtty dev,and save dlci open address status,if receive DLC0
+DISC or CLD frame,it can unregister the gsmtty dev by saving dlci address.
+
+Signed-off-by: Zhenguo Zhao <Zhenguo.Zhao1@unisoc.com>
+Link: https://lore.kernel.org/r/1629461872-26965-8-git-send-email-zhenguo6858@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_gsm.c | 57 +++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 53 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index 91ce8e6e889a..3038e5631be5 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -274,6 +274,10 @@ static DEFINE_SPINLOCK(gsm_mux_lock);
+ static struct tty_driver *gsm_tty_driver;
++/* Save dlci open address */
++static int addr_open[256] = { 0 };
++/* Save dlci open count */
++static int addr_cnt;
+ /*
+  *    This section of the driver logic implements the GSM encodings
+  *    both the basic and the 'advanced'. Reliable transport is not
+@@ -1191,6 +1195,7 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
+ }
+ static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
++static void gsm_dlci_close(struct gsm_dlci *dlci);
+ /**
+  *    gsm_control_message     -       DLCI 0 control processing
+@@ -1209,15 +1214,28 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
+ {
+       u8 buf[1];
+       unsigned long flags;
++      struct gsm_dlci *dlci;
++      int i;
++      int address;
+       switch (command) {
+       case CMD_CLD: {
+-              struct gsm_dlci *dlci = gsm->dlci[0];
++              if (addr_cnt > 0) {
++                      for (i = 0; i < addr_cnt; i++) {
++                              address = addr_open[i];
++                              dlci = gsm->dlci[address];
++                              gsm_dlci_close(dlci);
++                              addr_open[i] = 0;
++                      }
++              }
+               /* Modem wishes to close down */
++              dlci = gsm->dlci[0];
+               if (dlci) {
+                       dlci->dead = true;
+                       gsm->dead = true;
+-                      gsm_dlci_begin_close(dlci);
++                      gsm_dlci_close(dlci);
++                      addr_cnt = 0;
++                      gsm_response(gsm, 0, UA|PF);
+               }
+               }
+               break;
+@@ -1780,6 +1798,7 @@ static void gsm_queue(struct gsm_mux *gsm)
+       struct gsm_dlci *dlci;
+       u8 cr;
+       int address;
++      int i, j, k, address_tmp;
+       /* We have to sneak a look at the packet body to do the FCS.
+          A somewhat layering violation in the spec */
+@@ -1822,6 +1841,11 @@ static void gsm_queue(struct gsm_mux *gsm)
+               else {
+                       gsm_response(gsm, address, UA|PF);
+                       gsm_dlci_open(dlci);
++                      /* Save dlci open address */
++                      if (address) {
++                              addr_open[addr_cnt] = address;
++                              addr_cnt++;
++                      }
+               }
+               break;
+       case DISC|PF:
+@@ -1832,8 +1856,33 @@ static void gsm_queue(struct gsm_mux *gsm)
+                       return;
+               }
+               /* Real close complete */
+-              gsm_response(gsm, address, UA|PF);
+-              gsm_dlci_close(dlci);
++              if (!address) {
++                      if (addr_cnt > 0) {
++                              for (i = 0; i < addr_cnt; i++) {
++                                      address = addr_open[i];
++                                      dlci = gsm->dlci[address];
++                                      gsm_dlci_close(dlci);
++                                      addr_open[i] = 0;
++                              }
++                      }
++                      dlci = gsm->dlci[0];
++                      gsm_dlci_close(dlci);
++                      addr_cnt = 0;
++                      gsm_response(gsm, 0, UA|PF);
++              } else {
++                      gsm_response(gsm, address, UA|PF);
++                      gsm_dlci_close(dlci);
++                      /* clear dlci address */
++                      for (j = 0; j < addr_cnt; j++) {
++                              address_tmp = addr_open[j];
++                              if (address_tmp == address) {
++                                      for (k = j; k < addr_cnt; k++)
++                                              addr_open[k] = addr_open[k+1];
++                              addr_cnt--;
++                              break;
++                              }
++                      }
++              }
+               break;
+       case UA|PF:
+               if (cr == 0 || dlci == NULL)
+-- 
+2.35.1
+
diff --git a/queue-5.15/uapi-linux-stddef.h-add-include-guards.patch b/queue-5.15/uapi-linux-stddef.h-add-include-guards.patch
new file mode 100644 (file)
index 0000000..d9b3b21
--- /dev/null
@@ -0,0 +1,43 @@
+From 096444144cb973be2d86643d7b738f2c0b7aeb90 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 29 Mar 2022 10:12:52 -0700
+Subject: uapi/linux/stddef.h: Add include guards
+
+From: Tadeusz Struk <tadeusz.struk@linaro.org>
+
+[ Upstream commit 55037ed7bdc62151a726f5685f88afa6a82959b1 ]
+
+Add include guard wrapper define to uapi/linux/stddef.h to prevent macro
+redefinition errors when stddef.h is included more than once. This was not
+needed before since the only contents already used a redefinition test.
+
+Signed-off-by: Tadeusz Struk <tadeusz.struk@linaro.org>
+Link: https://lore.kernel.org/r/20220329171252.57279-1-tadeusz.struk@linaro.org
+Fixes: 50d7bd38c3aa ("stddef: Introduce struct_group() helper macro")
+Cc: stable@vger.kernel.org
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/uapi/linux/stddef.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h
+index 3021ea25a284..7837ba4fe728 100644
+--- a/include/uapi/linux/stddef.h
++++ b/include/uapi/linux/stddef.h
+@@ -1,4 +1,7 @@
+ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef _UAPI_LINUX_STDDEF_H
++#define _UAPI_LINUX_STDDEF_H
++
+ #include <linux/compiler_types.h>
+ #ifndef __always_inline
+@@ -41,3 +44,4 @@
+               struct { } __empty_ ## NAME; \
+               TYPE NAME[]; \
+       }
++#endif
+-- 
+2.35.1
+
diff --git a/queue-5.15/vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch b/queue-5.15/vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch
new file mode 100644 (file)
index 0000000..c5d2d2b
--- /dev/null
@@ -0,0 +1,57 @@
+From c264e9eda48ab0a18955994020bd9cd69abbb51e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 21 Mar 2022 16:13:03 +0200
+Subject: vdpa/mlx5: Avoid processing works if workqueue was destroyed
+
+From: Eli Cohen <elic@nvidia.com>
+
+[ Upstream commit ad6dc1daaf29f97f23cc810d60ee01c0e83f4c6b ]
+
+If mlx5_vdpa gets unloaded while a VM is running, the workqueue will be
+destroyed. However, vhost might still have reference to the kick
+function and might attempt to push new works. This could lead to null
+pointer dereference.
+
+To fix this, set mvdev->wq to NULL just before destroying and verify
+that the workqueue is not NULL in mlx5_vdpa_kick_vq before attempting to
+push a new work.
+
+Fixes: 5262912ef3cf ("vdpa/mlx5: Add support for control VQ and MAC setting")
+Signed-off-by: Eli Cohen <elic@nvidia.com>
+Link: https://lore.kernel.org/r/20220321141303.9586-1-elic@nvidia.com
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vdpa/mlx5/net/mlx5_vnet.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+index 174895372e7f..467a349dc26c 100644
+--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+@@ -1641,7 +1641,7 @@ static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx)
+               return;
+       if (unlikely(is_ctrl_vq_idx(mvdev, idx))) {
+-              if (!mvdev->cvq.ready)
++              if (!mvdev->wq || !mvdev->cvq.ready)
+                       return;
+               queue_work(mvdev->wq, &ndev->cvq_ent.work);
+@@ -2626,9 +2626,12 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *
+       struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev);
+       struct mlx5_vdpa_dev *mvdev = to_mvdev(dev);
+       struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
++      struct workqueue_struct *wq;
+       mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
+-      destroy_workqueue(mvdev->wq);
++      wq = mvdev->wq;
++      mvdev->wq = NULL;
++      destroy_workqueue(wq);
+       _vdpa_unregister_device(dev);
+       mgtdev->ndev = NULL;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.15/virtio-blk-avoid-preallocating-big-sgl-for-data.patch b/queue-5.15/virtio-blk-avoid-preallocating-big-sgl-for-data.patch
new file mode 100644 (file)
index 0000000..6b7cbd7
--- /dev/null
@@ -0,0 +1,298 @@
+From 15b1f99e4888efe37e66effb6352c03081ff3d36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Sep 2021 16:14:34 +0300
+Subject: virtio-blk: avoid preallocating big SGL for data
+
+From: Max Gurtovoy <mgurtovoy@nvidia.com>
+
+[ Upstream commit 02746e26c39ee473b975e0f68d1295abc92672ed ]
+
+No need to pre-allocate a big buffer for the IO SGL anymore. If a device
+has lots of deep queues, preallocation for the sg list can consume
+substantial amounts of memory. For HW virtio-blk device, nr_hw_queues
+can be 64 or 128 and each queue's depth might be 128. This means the
+resulting preallocation for the data SGLs is big.
+
+Switch to runtime allocation for SGL for lists longer than 2 entries.
+This is the approach used by NVMe drivers so it should be reasonable for
+virtio block as well. Runtime SGL allocation has always been the case
+for the legacy I/O path so this is nothing new.
+
+The preallocated small SGL depends on SG_CHAIN so if the ARCH doesn't
+support SG_CHAIN, use only runtime allocation for the SGL.
+
+Re-organize the setup of the IO request to fit the new sg chain
+mechanism.
+
+No performance degradation was seen (fio libaio engine with 16 jobs and
+128 iodepth):
+
+IO size      IOPs Rand Read (before/after)         IOPs Rand Write (before/after)
+--------     ---------------------------------    ----------------------------------
+512B          318K/316K                                    329K/325K
+
+4KB           323K/321K                                    353K/349K
+
+16KB          199K/208K                                    250K/275K
+
+128KB         36K/36.1K                                    39.2K/41.7K
+
+Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com>
+Reviewed-by: Israel Rukshin <israelr@nvidia.com>
+Link: https://lore.kernel.org/r/20210901131434.31158-1-mgurtovoy@nvidia.com
+Reviewed-by: Feng Li <lifeng1519@gmail.com>
+Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
+Tested-by: Stefan Hajnoczi <stefanha@redhat.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de> # kconfig fixups
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/Kconfig      |   1 +
+ drivers/block/virtio_blk.c | 156 ++++++++++++++++++++++++-------------
+ 2 files changed, 101 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index f93cb989241c..28ed157b1203 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -410,6 +410,7 @@ config XEN_BLKDEV_BACKEND
+ config VIRTIO_BLK
+       tristate "Virtio block driver"
+       depends on VIRTIO
++      select SG_POOL
+       help
+         This is the virtual block driver for virtio.  It can be used with
+           QEMU based VMMs (like KVM or Xen).  Say Y or M.
+diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
+index c05138a28475..ccc5770d7654 100644
+--- a/drivers/block/virtio_blk.c
++++ b/drivers/block/virtio_blk.c
+@@ -24,6 +24,12 @@
+ /* The maximum number of sg elements that fit into a virtqueue */
+ #define VIRTIO_BLK_MAX_SG_ELEMS 32768
++#ifdef CONFIG_ARCH_NO_SG_CHAIN
++#define VIRTIO_BLK_INLINE_SG_CNT      0
++#else
++#define VIRTIO_BLK_INLINE_SG_CNT      2
++#endif
++
+ static int major;
+ static DEFINE_IDA(vd_index_ida);
+@@ -77,6 +83,7 @@ struct virtio_blk {
+ struct virtblk_req {
+       struct virtio_blk_outhdr out_hdr;
+       u8 status;
++      struct sg_table sg_table;
+       struct scatterlist sg[];
+ };
+@@ -162,12 +169,92 @@ static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap)
+       return 0;
+ }
+-static inline void virtblk_request_done(struct request *req)
++static void virtblk_unmap_data(struct request *req, struct virtblk_req *vbr)
+ {
+-      struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
++      if (blk_rq_nr_phys_segments(req))
++              sg_free_table_chained(&vbr->sg_table,
++                                    VIRTIO_BLK_INLINE_SG_CNT);
++}
++
++static int virtblk_map_data(struct blk_mq_hw_ctx *hctx, struct request *req,
++              struct virtblk_req *vbr)
++{
++      int err;
++
++      if (!blk_rq_nr_phys_segments(req))
++              return 0;
++
++      vbr->sg_table.sgl = vbr->sg;
++      err = sg_alloc_table_chained(&vbr->sg_table,
++                                   blk_rq_nr_phys_segments(req),
++                                   vbr->sg_table.sgl,
++                                   VIRTIO_BLK_INLINE_SG_CNT);
++      if (unlikely(err))
++              return -ENOMEM;
++      return blk_rq_map_sg(hctx->queue, req, vbr->sg_table.sgl);
++}
++
++static void virtblk_cleanup_cmd(struct request *req)
++{
+       if (req->rq_flags & RQF_SPECIAL_PAYLOAD)
+               kfree(bvec_virt(&req->special_vec));
++}
++
++static int virtblk_setup_cmd(struct virtio_device *vdev, struct request *req,
++              struct virtblk_req *vbr)
++{
++      bool unmap = false;
++      u32 type;
++
++      vbr->out_hdr.sector = 0;
++
++      switch (req_op(req)) {
++      case REQ_OP_READ:
++              type = VIRTIO_BLK_T_IN;
++              vbr->out_hdr.sector = cpu_to_virtio64(vdev,
++                                                    blk_rq_pos(req));
++              break;
++      case REQ_OP_WRITE:
++              type = VIRTIO_BLK_T_OUT;
++              vbr->out_hdr.sector = cpu_to_virtio64(vdev,
++                                                    blk_rq_pos(req));
++              break;
++      case REQ_OP_FLUSH:
++              type = VIRTIO_BLK_T_FLUSH;
++              break;
++      case REQ_OP_DISCARD:
++              type = VIRTIO_BLK_T_DISCARD;
++              break;
++      case REQ_OP_WRITE_ZEROES:
++              type = VIRTIO_BLK_T_WRITE_ZEROES;
++              unmap = !(req->cmd_flags & REQ_NOUNMAP);
++              break;
++      case REQ_OP_DRV_IN:
++              type = VIRTIO_BLK_T_GET_ID;
++              break;
++      default:
++              WARN_ON_ONCE(1);
++              return BLK_STS_IOERR;
++      }
++
++      vbr->out_hdr.type = cpu_to_virtio32(vdev, type);
++      vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
++
++      if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) {
++              if (virtblk_setup_discard_write_zeroes(req, unmap))
++                      return BLK_STS_RESOURCE;
++      }
++
++      return 0;
++}
++
++static inline void virtblk_request_done(struct request *req)
++{
++      struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
++
++      virtblk_unmap_data(req, vbr);
++      virtblk_cleanup_cmd(req);
+       blk_mq_end_request(req, virtblk_result(vbr));
+ }
+@@ -225,57 +312,23 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
+       int qid = hctx->queue_num;
+       int err;
+       bool notify = false;
+-      bool unmap = false;
+-      u32 type;
+       BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
+-      switch (req_op(req)) {
+-      case REQ_OP_READ:
+-      case REQ_OP_WRITE:
+-              type = 0;
+-              break;
+-      case REQ_OP_FLUSH:
+-              type = VIRTIO_BLK_T_FLUSH;
+-              break;
+-      case REQ_OP_DISCARD:
+-              type = VIRTIO_BLK_T_DISCARD;
+-              break;
+-      case REQ_OP_WRITE_ZEROES:
+-              type = VIRTIO_BLK_T_WRITE_ZEROES;
+-              unmap = !(req->cmd_flags & REQ_NOUNMAP);
+-              break;
+-      case REQ_OP_DRV_IN:
+-              type = VIRTIO_BLK_T_GET_ID;
+-              break;
+-      default:
+-              WARN_ON_ONCE(1);
+-              return BLK_STS_IOERR;
+-      }
+-
+-      vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type);
+-      vbr->out_hdr.sector = type ?
+-              0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req));
+-      vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req));
++      err = virtblk_setup_cmd(vblk->vdev, req, vbr);
++      if (unlikely(err))
++              return err;
+       blk_mq_start_request(req);
+-      if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) {
+-              err = virtblk_setup_discard_write_zeroes(req, unmap);
+-              if (err)
+-                      return BLK_STS_RESOURCE;
+-      }
+-
+-      num = blk_rq_map_sg(hctx->queue, req, vbr->sg);
+-      if (num) {
+-              if (rq_data_dir(req) == WRITE)
+-                      vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT);
+-              else
+-                      vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN);
++      num = virtblk_map_data(hctx, req, vbr);
++      if (unlikely(num < 0)) {
++              virtblk_cleanup_cmd(req);
++              return BLK_STS_RESOURCE;
+       }
+       spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
+-      err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
++      err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg_table.sgl, num);
+       if (err) {
+               virtqueue_kick(vblk->vqs[qid].vq);
+               /* Don't stop the queue if -ENOMEM: we may have failed to
+@@ -284,6 +337,8 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
+               if (err == -ENOSPC)
+                       blk_mq_stop_hw_queue(hctx);
+               spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
++              virtblk_unmap_data(req, vbr);
++              virtblk_cleanup_cmd(req);
+               switch (err) {
+               case -ENOSPC:
+                       return BLK_STS_DEV_RESOURCE;
+@@ -660,16 +715,6 @@ static const struct attribute_group *virtblk_attr_groups[] = {
+       NULL,
+ };
+-static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq,
+-              unsigned int hctx_idx, unsigned int numa_node)
+-{
+-      struct virtio_blk *vblk = set->driver_data;
+-      struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq);
+-
+-      sg_init_table(vbr->sg, vblk->sg_elems);
+-      return 0;
+-}
+-
+ static int virtblk_map_queues(struct blk_mq_tag_set *set)
+ {
+       struct virtio_blk *vblk = set->driver_data;
+@@ -682,7 +727,6 @@ static const struct blk_mq_ops virtio_mq_ops = {
+       .queue_rq       = virtio_queue_rq,
+       .commit_rqs     = virtio_commit_rqs,
+       .complete       = virtblk_request_done,
+-      .init_request   = virtblk_init_request,
+       .map_queues     = virtblk_map_queues,
+ };
+@@ -762,7 +806,7 @@ static int virtblk_probe(struct virtio_device *vdev)
+       vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+       vblk->tag_set.cmd_size =
+               sizeof(struct virtblk_req) +
+-              sizeof(struct scatterlist) * sg_elems;
++              sizeof(struct scatterlist) * VIRTIO_BLK_INLINE_SG_CNT;
+       vblk->tag_set.driver_data = vblk;
+       vblk->tag_set.nr_hw_queues = vblk->num_vqs;
+-- 
+2.35.1
+