]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.10
authorSasha Levin <sashal@kernel.org>
Sun, 6 Oct 2024 15:11:22 +0000 (11:11 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 6 Oct 2024 15:11:22 +0000 (11:11 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
189 files changed:
queue-6.10/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch [new file with mode: 0644]
queue-6.10/acpi-ec-do-not-release-locks-during-operation-region.patch [new file with mode: 0644]
queue-6.10/acpi-pad-fix-crash-in-exit_round_robin.patch [new file with mode: 0644]
queue-6.10/acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch [new file with mode: 0644]
queue-6.10/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch [new file with mode: 0644]
queue-6.10/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch [new file with mode: 0644]
queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch [new file with mode: 0644]
queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch [new file with mode: 0644]
queue-6.10/acpica-iasl-handle-empty-connection_node.patch [new file with mode: 0644]
queue-6.10/alsa-asihpi-fix-potential-oob-array-access.patch [new file with mode: 0644]
queue-6.10/alsa-control-take-power_ref-lock-primarily.patch [new file with mode: 0644]
queue-6.10/alsa-hdsp-break-infinite-midi-input-flush-loop.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-add-logitech-audio-profile-quirk.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-define-macros-for-quirk-table-entries.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch [new file with mode: 0644]
queue-6.10/alsa-usb-audio-support-multiple-control-interfaces.patch [new file with mode: 0644]
queue-6.10/arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch [new file with mode: 0644]
queue-6.10/asoc-codecs-wsa883x-handle-reading-version-failure.patch [new file with mode: 0644]
queue-6.10/asoc-intel-boards-always-check-the-result-of-acpi_de.patch [new file with mode: 0644]
queue-6.10/ata-pata_serverworks-do-not-use-the-term-blacklist.patch [new file with mode: 0644]
queue-6.10/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch [new file with mode: 0644]
queue-6.10/blk_iocost-fix-more-out-of-bound-shifts.patch [new file with mode: 0644]
queue-6.10/block-fix-integer-overflow-in-blksecdiscard.patch [new file with mode: 0644]
queue-6.10/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch [new file with mode: 0644]
queue-6.10/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch [new file with mode: 0644]
queue-6.10/bnxt_en-extend-maximum-length-of-version-string-by-1.patch [new file with mode: 0644]
queue-6.10/bpf-fix-a-sdiv-overflow-issue.patch [new file with mode: 0644]
queue-6.10/bpf-make-the-pointer-returned-by-iter-next-method-va.patch [new file with mode: 0644]
queue-6.10/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch [new file with mode: 0644]
queue-6.10/bpftool-fix-undefined-behavior-in-qsort-null-0.patch [new file with mode: 0644]
queue-6.10/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch [new file with mode: 0644]
queue-6.10/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch [new file with mode: 0644]
queue-6.10/coredump-standartize-and-fix-logging.patch [new file with mode: 0644]
queue-6.10/crypto-hisilicon-fix-missed-error-branch.patch [new file with mode: 0644]
queue-6.10/crypto-octeontx-fix-authenc-setkey.patch [new file with mode: 0644]
queue-6.10/crypto-octeontx2-fix-authenc-setkey.patch [new file with mode: 0644]
queue-6.10/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch [new file with mode: 0644]
queue-6.10/crypto-x86-sha256-add-parentheses-around-macros-sing.patch [new file with mode: 0644]
queue-6.10/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch-29584 [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-check-null-initialized-variables.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-check-null-pointers-before-using-dc-.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-check-null-pointers-before-using-the.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-check-phantom_stream-before-it-is-us.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-check-stream-before-comparing-them.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-handle-null-stream_status-in-planes_.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-initialize-get_bytes_per_element-s-d.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch [new file with mode: 0644]
queue-6.10/drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch [new file with mode: 0644]
queue-6.10/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-add-raven1-gfxoff-quirk.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177 [new file with mode: 0644]
queue-6.10/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch [new file with mode: 0644]
queue-6.10/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch [new file with mode: 0644]
queue-6.10/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch [new file with mode: 0644]
queue-6.10/drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch [new file with mode: 0644]
queue-6.10/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch [new file with mode: 0644]
queue-6.10/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch [new file with mode: 0644]
queue-6.10/drm-printer-allow-null-data-in-devcoredump-printer.patch [new file with mode: 0644]
queue-6.10/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch [new file with mode: 0644]
queue-6.10/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch [new file with mode: 0644]
queue-6.10/drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch [new file with mode: 0644]
queue-6.10/drm-xe-drop-warn-on-xe_guc_pc_gucrc_disable-in-guc-p.patch [new file with mode: 0644]
queue-6.10/drm-xe-hdcp-check-gsc-structure-validity.patch [new file with mode: 0644]
queue-6.10/drm-xe-use-topology-to-determine-page-fault-queue-si.patch [new file with mode: 0644]
queue-6.10/e1000e-avoid-failing-the-system-during-pm_suspend.patch [new file with mode: 0644]
queue-6.10/ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch [new file with mode: 0644]
queue-6.10/ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch [new file with mode: 0644]
queue-6.10/ext4-ext4_search_dir-should-return-a-proper-error.patch [new file with mode: 0644]
queue-6.10/ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch [new file with mode: 0644]
queue-6.10/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch [new file with mode: 0644]
queue-6.10/fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch [new file with mode: 0644]
queue-6.10/fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch [new file with mode: 0644]
queue-6.10/hid-i2c-hid-ensure-various-commands-do-not-interfere.patch [new file with mode: 0644]
queue-6.10/hid-ignore-battery-for-all-elan-i2c-hid-devices.patch [new file with mode: 0644]
queue-6.10/hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch [new file with mode: 0644]
queue-6.10/hwmon-nct6775-add-g15cf-to-asus-wmi-monitoring-list.patch [new file with mode: 0644]
queue-6.10/ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch [new file with mode: 0644]
queue-6.10/iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch [new file with mode: 0644]
queue-6.10/iommu-arm-smmu-v3-do-not-use-devm-for-the-cd-table-a.patch [new file with mode: 0644]
queue-6.10/iommu-arm-smmu-v3-match-stall-behaviour-for-s2.patch [new file with mode: 0644]
queue-6.10/iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch [new file with mode: 0644]
queue-6.10/iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch [new file with mode: 0644]
queue-6.10/iommu-vt-d-unconditionally-flush-device-tlb-for-pasi.patch [new file with mode: 0644]
queue-6.10/ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch [new file with mode: 0644]
queue-6.10/ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch [new file with mode: 0644]
queue-6.10/jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch [new file with mode: 0644]
queue-6.10/jfs-fix-uaf-in-dbfreebits.patch [new file with mode: 0644]
queue-6.10/jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch [new file with mode: 0644]
queue-6.10/jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch [new file with mode: 0644]
queue-6.10/ksmbd-add-refcnt-to-ksmbd_conn-struct.patch [new file with mode: 0644]
queue-6.10/net-atlantic-avoid-warning-about-potential-string-tr.patch [new file with mode: 0644]
queue-6.10/net-hisilicon-hip04-fix-of-node-leak-in-probe.patch [new file with mode: 0644]
queue-6.10/net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch [new file with mode: 0644]
queue-6.10/net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch [new file with mode: 0644]
queue-6.10/net-mvpp2-increase-size-of-queue_name-buffer.patch [new file with mode: 0644]
queue-6.10/net-napi-prevent-overflow-of-napi_defer_hard_irqs.patch [new file with mode: 0644]
queue-6.10/net-phy-check-for-read-errors-in-siocgmiireg.patch [new file with mode: 0644]
queue-6.10/net-sched-consistently-use-rcu_replace_pointer-in-ta.patch [new file with mode: 0644]
queue-6.10/net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch [new file with mode: 0644]
queue-6.10/netdev-genl-set-extack-and-fix-error-on-napi-get.patch [new file with mode: 0644]
queue-6.10/netfs-cancel-dirty-folios-that-have-no-storage-desti.patch [new file with mode: 0644]
queue-6.10/netpoll-ensure-clean-state-on-setup-failures.patch [new file with mode: 0644]
queue-6.10/nfp-use-irqf_no_autoen-flag-in-request_irq.patch [new file with mode: 0644]
queue-6.10/nvme-keyring-restrict-match-length-for-version-1-ide.patch [new file with mode: 0644]
queue-6.10/nvme-tcp-check-for-invalidated-or-revoked-key.patch [new file with mode: 0644]
queue-6.10/nvme-tcp-sanitize-tls-key-handling.patch [new file with mode: 0644]
queue-6.10/of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch [new file with mode: 0644]
queue-6.10/ovl-fsync-after-metadata-copy-up.patch [new file with mode: 0644]
queue-6.10/perf-fix-event_function_call-locking.patch [new file with mode: 0644]
queue-6.10/perf-x86-avoid-missing-caller-address-in-stack-trace.patch [new file with mode: 0644]
queue-6.10/platform-mellanox-mlxbf-pmc-fix-lockdep-warning.patch [new file with mode: 0644]
queue-6.10/platform-x86-amd-pmf-add-quirk-for-tuf-gaming-a14.patch [new file with mode: 0644]
queue-6.10/platform-x86-lenovo-ymc-ignore-the-0x0-state.patch [new file with mode: 0644]
queue-6.10/platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch [new file with mode: 0644]
queue-6.10/platform-x86-x86-android-tablets-adjust-xiaomi-pad-2.patch [new file with mode: 0644]
queue-6.10/pmdomain-core-don-t-hold-the-genpd-lock-when-calling.patch [new file with mode: 0644]
queue-6.10/power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch [new file with mode: 0644]
queue-6.10/powerpc-pseries-use-correct-data-types-from-pseries_.patch [new file with mode: 0644]
queue-6.10/proc-add-config-param-to-block-forcing-mem-writes.patch [new file with mode: 0644]
queue-6.10/rcu-tasks-fix-access-non-existent-percpu-rtpcp-varia.patch [new file with mode: 0644]
queue-6.10/rcuscale-provide-clear-error-when-async-specified-wi.patch [new file with mode: 0644]
queue-6.10/scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch [new file with mode: 0644]
queue-6.10/scsi-lpfc-fix-unsolicited-flogi-kref-imbalance-when-.patch [new file with mode: 0644]
queue-6.10/scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch [new file with mode: 0644]
queue-6.10/scsi-lpfc-validate-hdwq-pointers-before-dereferencin.patch [new file with mode: 0644]
queue-6.10/scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch [new file with mode: 0644]
queue-6.10/scsi-smartpqi-add-new-controller-pci-ids.patch [new file with mode: 0644]
queue-6.10/scsi-smartpqi-add-new-controller-pci-ids.patch-21617 [new file with mode: 0644]
queue-6.10/scsi-smartpqi-correct-stream-detection.patch [new file with mode: 0644]
queue-6.10/selftests-nolibc-avoid-passing-null-to-printf-s.patch [new file with mode: 0644]
queue-6.10/series
queue-6.10/tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch [new file with mode: 0644]
queue-6.10/tipc-guard-against-string-buffer-overrun.patch [new file with mode: 0644]
queue-6.10/tools-hv-add-memory-allocation-check-in-hv_fcopy_sta.patch [new file with mode: 0644]
queue-6.10/tools-nolibc-powerpc-limit-stack-protector-workaroun.patch [new file with mode: 0644]
queue-6.10/tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch [new file with mode: 0644]
queue-6.10/wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch [new file with mode: 0644]
queue-6.10/wifi-ath12k-fix-array-out-of-bound-access-in-soc-sta.patch [new file with mode: 0644]
queue-6.10/wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch [new file with mode: 0644]
queue-6.10/wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch [new file with mode: 0644]
queue-6.10/wifi-cfg80211-set-correct-chandef-when-starting-cac.patch [new file with mode: 0644]
queue-6.10/wifi-iwlwifi-allow-only-cn-mcc-from-wrdd.patch [new file with mode: 0644]
queue-6.10/wifi-iwlwifi-mvm-avoid-null-pointer-dereference.patch [new file with mode: 0644]
queue-6.10/wifi-iwlwifi-mvm-drop-wrong-sta-selection-in-tx.patch [new file with mode: 0644]
queue-6.10/wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch [new file with mode: 0644]
queue-6.10/wifi-iwlwifi-mvm-use-correct-key-iteration.patch [new file with mode: 0644]
queue-6.10/wifi-mac80211-fix-rcu-list-iterations.patch [new file with mode: 0644]
queue-6.10/wifi-mt76-mt7915-add-dummy-hw-offload-of-ieee-802.11.patch [new file with mode: 0644]
queue-6.10/wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch [new file with mode: 0644]
queue-6.10/wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch [new file with mode: 0644]
queue-6.10/wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch [new file with mode: 0644]
queue-6.10/wifi-rtw88-select-want_dev_coredump.patch [new file with mode: 0644]
queue-6.10/wifi-rtw89-avoid-reading-out-of-bounds-when-loading-.patch [new file with mode: 0644]
queue-6.10/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch [new file with mode: 0644]
queue-6.10/wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch [new file with mode: 0644]
queue-6.10/x86-apic-remove-logical-destination-mode-for-64-bit.patch [new file with mode: 0644]
queue-6.10/x86-bugs-add-missing-no_ssb-flag.patch [new file with mode: 0644]
queue-6.10/x86-bugs-fix-handling-when-srso-mitigation-is-disabl.patch [new file with mode: 0644]
queue-6.10/x86-ioapic-handle-allocation-failures-gracefully.patch [new file with mode: 0644]
queue-6.10/x86-kexec-add-efi-config-table-identity-mapping-for-.patch [new file with mode: 0644]
queue-6.10/x86-mm-ident_map-use-gbpages-only-where-full-gb-page.patch [new file with mode: 0644]
queue-6.10/x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch [new file with mode: 0644]
queue-6.10/x86-pkeys-restore-altstack-access-in-sigreturn.patch [new file with mode: 0644]
queue-6.10/x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch [new file with mode: 0644]

diff --git a/queue-6.10/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch b/queue-6.10/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch
new file mode 100644 (file)
index 0000000..e811d5c
--- /dev/null
@@ -0,0 +1,74 @@
+From 37388a81aab1a4c4fcf870fc68df3fb28291c49e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Sep 2024 22:15:24 -0500
+Subject: ACPI: CPPC: Add support for setting EPP register in FFH
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mario Limonciello <mario.limonciello@amd.com>
+
+[ Upstream commit aaf21ac93909e08a12931173336bdb52ac8499f1 ]
+
+Some Asus AMD systems are reported to not be able to change EPP values
+because the BIOS doesn't advertise support for the CPPC MSR and the PCC
+region is not configured.
+
+However the ACPI 6.2 specification allows CPC registers to be declared
+in FFH:
+```
+Starting with ACPI Specification 6.2, all _CPC registers can be in
+PCC, System Memory, System IO, or Functional Fixed Hardware address
+spaces. OSPM support for this more flexible register space scheme
+is indicated by the “Flexible Address Space for CPPC Registers” _OSC
+bit.
+```
+
+If this _OSC has been set allow using FFH to configure EPP.
+
+Reported-by: al0uette@outlook.com
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218686
+Suggested-by: al0uette@outlook.com
+Tested-by: vderp@icloud.com
+Tested-by: al0uette@outlook.com
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Link: https://patch.msgid.link/20240910031524.106387-1-superm1@kernel.org
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/cppc_acpi.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
+index 2a588e4ed4af4..6a048d44fbcf6 100644
+--- a/drivers/acpi/cppc_acpi.c
++++ b/drivers/acpi/cppc_acpi.c
+@@ -103,6 +103,11 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
+                               (cpc)->cpc_entry.reg.space_id ==        \
+                               ACPI_ADR_SPACE_PLATFORM_COMM)
++/* Check if a CPC register is in FFH */
++#define CPC_IN_FFH(cpc) ((cpc)->type == ACPI_TYPE_BUFFER &&           \
++                              (cpc)->cpc_entry.reg.space_id ==        \
++                              ACPI_ADR_SPACE_FIXED_HARDWARE)
++
+ /* Check if a CPC register is in SystemMemory */
+ #define CPC_IN_SYSTEM_MEMORY(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
+                               (cpc)->cpc_entry.reg.space_id ==        \
+@@ -1519,9 +1524,12 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
+               /* after writing CPC, transfer the ownership of PCC to platform */
+               ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+               up_write(&pcc_ss_data->pcc_lock);
++      } else if (osc_cpc_flexible_adr_space_confirmed &&
++                 CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) {
++              ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
+       } else {
+               ret = -ENOTSUPP;
+-              pr_debug("_CPC in PCC is not supported\n");
++              pr_debug("_CPC in PCC and _CPC in FFH are not supported\n");
+       }
+       return ret;
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpi-ec-do-not-release-locks-during-operation-region.patch b/queue-6.10/acpi-ec-do-not-release-locks-during-operation-region.patch
new file mode 100644 (file)
index 0000000..05feed1
--- /dev/null
@@ -0,0 +1,166 @@
+From 076c028fbcdc9eb276b319b82f74e1d62c54d959 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jul 2024 18:26:54 +0200
+Subject: ACPI: EC: Do not release locks during operation region accesses
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit dc171114926ec390ab90f46534545420ec03e458 ]
+
+It is not particularly useful to release locks (the EC mutex and the
+ACPI global lock, if present) and re-acquire them immediately thereafter
+during EC address space accesses in acpi_ec_space_handler().
+
+First, releasing them for a while before grabbing them again does not
+really help anyone because there may not be enough time for another
+thread to acquire them.
+
+Second, if another thread successfully acquires them and carries out
+a new EC write or read in the middle if an operation region access in
+progress, it may confuse the EC firmware, especially after the burst
+mode has been enabled.
+
+Finally, manipulating the locks after writing or reading every single
+byte of data is overhead that it is better to avoid.
+
+Accordingly, modify the code to carry out EC address space accesses
+entirely without releasing the locks.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patch.msgid.link/12473338.O9o76ZdvQC@rjwysocki.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/ec.c | 55 +++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 49 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
+index 38d2f6e6b12b4..25399f6dde7e2 100644
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
+       unsigned long tmp;
+       int ret = 0;
++      if (t->rdata)
++              memset(t->rdata, 0, t->rlen);
++
+       /* start transaction */
+       spin_lock_irqsave(&ec->lock, tmp);
+       /* Enable GPE for command processing (IBF=0/OBF=1) */
+@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
+       if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
+               return -EINVAL;
+-      if (t->rdata)
+-              memset(t->rdata, 0, t->rlen);
+       mutex_lock(&ec->mutex);
+       if (ec->global_lock) {
+@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec)
+                               .wdata = NULL, .rdata = &d,
+                               .wlen = 0, .rlen = 1};
+-      return acpi_ec_transaction(ec, &t);
++      return acpi_ec_transaction_unlocked(ec, &t);
+ }
+ static int acpi_ec_burst_disable(struct acpi_ec *ec)
+@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
+                               .wlen = 0, .rlen = 0};
+       return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
+-                              acpi_ec_transaction(ec, &t) : 0;
++                              acpi_ec_transaction_unlocked(ec, &t) : 0;
+ }
+ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+       return result;
+ }
++static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data)
++{
++      int result;
++      u8 d;
++      struct transaction t = {.command = ACPI_EC_COMMAND_READ,
++                              .wdata = &address, .rdata = &d,
++                              .wlen = 1, .rlen = 1};
++
++      result = acpi_ec_transaction_unlocked(ec, &t);
++      *data = d;
++      return result;
++}
++
+ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+ {
+       u8 wdata[2] = { address, data };
+@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+       return acpi_ec_transaction(ec, &t);
+ }
++static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data)
++{
++      u8 wdata[2] = { address, data };
++      struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
++                              .wdata = wdata, .rdata = NULL,
++                              .wlen = 2, .rlen = 0};
++
++      return acpi_ec_transaction_unlocked(ec, &t);
++}
++
+ int ec_read(u8 addr, u8 *val)
+ {
+       int err;
+@@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
+       struct acpi_ec *ec = handler_context;
+       int result = 0, i, bytes = bits / 8;
+       u8 *value = (u8 *)value64;
++      u32 glk;
+       if ((address > 0xFF) || !value || !handler_context)
+               return AE_BAD_PARAMETER;
+@@ -1330,13 +1355,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
+       if (function != ACPI_READ && function != ACPI_WRITE)
+               return AE_BAD_PARAMETER;
++      mutex_lock(&ec->mutex);
++
++      if (ec->global_lock) {
++              acpi_status status;
++
++              status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
++              if (ACPI_FAILURE(status)) {
++                      result = -ENODEV;
++                      goto unlock;
++              }
++      }
++
+       if (ec->busy_polling || bits > 8)
+               acpi_ec_burst_enable(ec);
+       for (i = 0; i < bytes; ++i, ++address, ++value) {
+               result = (function == ACPI_READ) ?
+-                      acpi_ec_read(ec, address, value) :
+-                      acpi_ec_write(ec, address, *value);
++                      acpi_ec_read_unlocked(ec, address, value) :
++                      acpi_ec_write_unlocked(ec, address, *value);
+               if (result < 0)
+                       break;
+       }
+@@ -1344,6 +1381,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
+       if (ec->busy_polling || bits > 8)
+               acpi_ec_burst_disable(ec);
++      if (ec->global_lock)
++              acpi_release_global_lock(glk);
++
++unlock:
++      mutex_unlock(&ec->mutex);
++
+       switch (result) {
+       case -EINVAL:
+               return AE_BAD_PARAMETER;
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpi-pad-fix-crash-in-exit_round_robin.patch b/queue-6.10/acpi-pad-fix-crash-in-exit_round_robin.patch
new file mode 100644 (file)
index 0000000..2063e08
--- /dev/null
@@ -0,0 +1,96 @@
+From c82a268eeb0d10b9b08ebd401ff7243df48358d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 23:13:52 +0900
+Subject: ACPI: PAD: fix crash in exit_round_robin()
+
+From: Seiji Nishikawa <snishika@redhat.com>
+
+[ Upstream commit 0a2ed70a549e61c5181bad5db418d223b68ae932 ]
+
+The kernel occasionally crashes in cpumask_clear_cpu(), which is called
+within exit_round_robin(), because when executing clear_bit(nr, addr) with
+nr set to 0xffffffff, the address calculation may cause misalignment within
+the memory, leading to access to an invalid memory address.
+
+----------
+BUG: unable to handle kernel paging request at ffffffffe0740618
+        ...
+CPU: 3 PID: 2919323 Comm: acpi_pad/14 Kdump: loaded Tainted: G           OE  X --------- -  - 4.18.0-425.19.2.el8_7.x86_64 #1
+        ...
+RIP: 0010:power_saving_thread+0x313/0x411 [acpi_pad]
+Code: 89 cd 48 89 d3 eb d1 48 c7 c7 55 70 72 c0 e8 64 86 b0 e4 c6 05 0d a1 02 00 01 e9 bc fd ff ff 45 89 e4 42 8b 04 a5 20 82 72 c0 <f0> 48 0f b3 05 f4 9c 01 00 42 c7 04 a5 20 82 72 c0 ff ff ff ff 31
+RSP: 0018:ff72a5d51fa77ec8 EFLAGS: 00010202
+RAX: 00000000ffffffff RBX: ff462981e5d8cb80 RCX: 0000000000000000
+RDX: 0000000000000000 RSI: 0000000000000246 RDI: 0000000000000246
+RBP: ff46297556959d80 R08: 0000000000000382 R09: ff46297c8d0f38d8
+R10: 0000000000000000 R11: 0000000000000001 R12: 000000000000000e
+R13: 0000000000000000 R14: ffffffffffffffff R15: 000000000000000e
+FS:  0000000000000000(0000) GS:ff46297a800c0000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: ffffffffe0740618 CR3: 0000007e20410004 CR4: 0000000000771ee0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+PKRU: 55555554
+Call Trace:
+ ? acpi_pad_add+0x120/0x120 [acpi_pad]
+ kthread+0x10b/0x130
+ ? set_kthread_struct+0x50/0x50
+ ret_from_fork+0x1f/0x40
+        ...
+CR2: ffffffffe0740618
+
+crash> dis -lr ffffffffc0726923
+        ...
+/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 114
+0xffffffffc0726918 <power_saving_thread+776>:  mov    %r12d,%r12d
+/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 325
+0xffffffffc072691b <power_saving_thread+779>:  mov    -0x3f8d7de0(,%r12,4),%eax
+/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./arch/x86/include/asm/bitops.h: 80
+0xffffffffc0726923 <power_saving_thread+787>:  lock btr %rax,0x19cf4(%rip)        # 0xffffffffc0740620 <pad_busy_cpus_bits>
+
+crash> px tsk_in_cpu[14]
+$66 = 0xffffffff
+
+crash> px 0xffffffffc072692c+0x19cf4
+$99 = 0xffffffffc0740620
+
+crash> sym 0xffffffffc0740620
+ffffffffc0740620 (b) pad_busy_cpus_bits [acpi_pad]
+
+crash> px pad_busy_cpus_bits[0]
+$42 = 0xfffc0
+----------
+
+To fix this, ensure that tsk_in_cpu[tsk_index] != -1 before calling
+cpumask_clear_cpu() in exit_round_robin(), just as it is done in
+round_robin_cpu().
+
+Signed-off-by: Seiji Nishikawa <snishika@redhat.com>
+Link: https://patch.msgid.link/20240825141352.25280-1-snishika@redhat.com
+[ rjw: Subject edit, avoid updates to the same value ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpi_pad.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
+index bd1ad07f02907..e84509b19f94d 100644
+--- a/drivers/acpi/acpi_pad.c
++++ b/drivers/acpi/acpi_pad.c
+@@ -132,8 +132,10 @@ static void exit_round_robin(unsigned int tsk_index)
+ {
+       struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+-      cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+-      tsk_in_cpu[tsk_index] = -1;
++      if (tsk_in_cpu[tsk_index] != -1) {
++              cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
++              tsk_in_cpu[tsk_index] = -1;
++      }
+ }
+ static unsigned int idle_pct = 5; /* percentage */
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch b/queue-6.10/acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch
new file mode 100644 (file)
index 0000000..da7d8c6
--- /dev/null
@@ -0,0 +1,48 @@
+From f40ceea36548d65154cbf4e71a6133f4fdc428c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 21:43:05 -0400
+Subject: ACPI: resource: Skip IRQ override on Asus Vivobook Go E1404GAB
+
+From: Tamim Khan <tamim@fusetak.com>
+
+[ Upstream commit 49e9cc315604972cc14868cb67831e3e8c3f1470 ]
+
+Like other Asus Vivobooks, the Asus Vivobook Go E1404GAB has a DSDT
+that describes IRQ 1 as ActiveLow, while the kernel overrides to Edge_High.
+
+This override prevents the internal keyboard from working.
+
+Fix the problem by adding this laptop to the table that prevents the kernel
+from overriding the IRQ.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=219212
+Signed-off-by: Tamim Khan <tamim@fusetak.com>
+Link: https://patch.msgid.link/20240903014317.38858-1-tamim@fusetak.com
+[ rjw: Changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/resource.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
+index cb2aacbb93357..8a4726e2eb693 100644
+--- a/drivers/acpi/resource.c
++++ b/drivers/acpi/resource.c
+@@ -503,6 +503,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
+                       DMI_MATCH(DMI_BOARD_NAME, "B2502FBA"),
+               },
+       },
++      {
++              /* Asus Vivobook Go E1404GAB */
++              .matches = {
++                      DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++                      DMI_MATCH(DMI_BOARD_NAME, "E1404GAB"),
++              },
++      },
+       {
+               /* Asus Vivobook E1504GA */
+               .matches = {
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch b/queue-6.10/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch
new file mode 100644 (file)
index 0000000..4833288
--- /dev/null
@@ -0,0 +1,45 @@
+From 868c366b71d3a9eddc22f45b52a14a0ce2dd4c36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 7 Sep 2024 14:44:19 +0200
+Subject: ACPI: video: Add force_vendor quirk for Panasonic Toughbook CF-18
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit eb7b0f12e13ba99e64e3a690c2166895ed63b437 ]
+
+The Panasonic Toughbook CF-18 advertises both native and vendor backlight
+control interfaces. But only the vendor one actually works.
+
+acpi_video_get_backlight_type() will pick the non working native backlight
+by default, add a quirk to select the working vendor backlight instead.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patch.msgid.link/20240907124419.21195-1-hdegoede@redhat.com
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/video_detect.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
+index 75a5f559402f8..428a7399fe04a 100644
+--- a/drivers/acpi/video_detect.c
++++ b/drivers/acpi/video_detect.c
+@@ -254,6 +254,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
+               DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"),
+               },
+       },
++      {
++       .callback = video_detect_force_vendor,
++       /* Panasonic Toughbook CF-18 */
++       .matches = {
++              DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"),
++              DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
++              },
++      },
+       /*
+        * Toshiba models with Transflective display, these need to use
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch b/queue-6.10/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch
new file mode 100644 (file)
index 0000000..c34ca1c
--- /dev/null
@@ -0,0 +1,41 @@
+From 145ecb817f92512d9578d61098adddcaae580434 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 14:05:48 +0800
+Subject: ACPICA: check null return of ACPI_ALLOCATE_ZEROED() in
+ acpi_db_convert_to_package()
+
+From: Pei Xiao <xiaopei01@kylinos.cn>
+
+[ Upstream commit a5242874488eba2b9062985bf13743c029821330 ]
+
+ACPICA commit 4d4547cf13cca820ff7e0f859ba83e1a610b9fd0
+
+ACPI_ALLOCATE_ZEROED() may fail, elements might be NULL and will cause
+NULL pointer dereference later.
+
+Link: https://github.com/acpica/acpica/commit/4d4547cf
+Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn>
+Link: https://patch.msgid.link/tencent_4A21A2865B8B0A0D12CAEBEB84708EDDB505@qq.com
+[ rjw: Subject and changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/dbconvert.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
+index 2b84ac093698a..8dbab69320499 100644
+--- a/drivers/acpi/acpica/dbconvert.c
++++ b/drivers/acpi/acpica/dbconvert.c
+@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object)
+       elements =
+           ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
+                                sizeof(union acpi_object));
++      if (!elements)
++              return (AE_NO_MEMORY);
+       this = string;
+       for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch b/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch
new file mode 100644 (file)
index 0000000..f5e6466
--- /dev/null
@@ -0,0 +1,90 @@
+From c0c6bf048a70b21942f7ec237237ebe80fdfe5ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Apr 2024 21:50:33 +0200
+Subject: ACPICA: Fix memory leak if acpi_ps_get_next_field() fails
+
+From: Armin Wolf <W_Armin@gmx.de>
+
+[ Upstream commit e6169a8ffee8a012badd8c703716e761ce851b15 ]
+
+ACPICA commit 1280045754264841b119a5ede96cd005bc09b5a7
+
+If acpi_ps_get_next_field() fails, the previously created field list
+needs to be properly disposed before returning the status code.
+
+Link: https://github.com/acpica/acpica/commit/12800457
+Signed-off-by: Armin Wolf <W_Armin@gmx.de>
+[ rjw: Rename local variable to avoid compiler confusion ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/psargs.c | 39 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
+index 7debfd5ce0d86..28582adfc0aca 100644
+--- a/drivers/acpi/acpica/psargs.c
++++ b/drivers/acpi/acpica/psargs.c
+@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state);
+ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
+                                                      *parser_state);
++static void acpi_ps_free_field_list(union acpi_parse_object *start);
++
+ /*******************************************************************************
+  *
+  * FUNCTION:    acpi_ps_get_next_package_length
+@@ -683,6 +685,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
+       return_PTR(field);
+ }
++/*******************************************************************************
++ *
++ * FUNCTION:    acpi_ps_free_field_list
++ *
++ * PARAMETERS:  start               - First Op in field list
++ *
++ * RETURN:      None.
++ *
++ * DESCRIPTION: Free all Op objects inside a field list.
++ *
++ ******************************************************************************/
++
++static void acpi_ps_free_field_list(union acpi_parse_object *start)
++{
++      union acpi_parse_object *cur = start;
++      union acpi_parse_object *next;
++      union acpi_parse_object *arg;
++
++      while (cur) {
++              next = cur->common.next;
++
++              /* AML_INT_CONNECTION_OP can have a single argument */
++
++              arg = acpi_ps_get_arg(cur, 0);
++              if (arg) {
++                      acpi_ps_free_op(arg);
++              }
++
++              acpi_ps_free_op(cur);
++              cur = next;
++      }
++}
++
+ /*******************************************************************************
+  *
+  * FUNCTION:    acpi_ps_get_next_arg
+@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+                       while (parser_state->aml < parser_state->pkg_end) {
+                               field = acpi_ps_get_next_field(parser_state);
+                               if (!field) {
++                                      if (arg) {
++                                              acpi_ps_free_field_list(arg);
++                                      }
++
+                                       return_ACPI_STATUS(AE_NO_MEMORY);
+                               }
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch b/queue-6.10/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch
new file mode 100644 (file)
index 0000000..df8f5e6
--- /dev/null
@@ -0,0 +1,55 @@
+From 6c76b2d767d19ba6b7644b9c63968e96feba1472 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Apr 2024 20:50:11 +0200
+Subject: ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails
+
+From: Armin Wolf <W_Armin@gmx.de>
+
+[ Upstream commit 5accb265f7a1b23e52b0ec42313d1e12895552f4 ]
+
+ACPICA commit 2802af722bbde7bf1a7ac68df68e179e2555d361
+
+If acpi_ps_get_next_namepath() fails, the previously allocated
+union acpi_parse_object needs to be freed before returning the
+status code.
+
+The issue was first being reported on the Linux ACPI mailing list:
+
+Link: https://lore.kernel.org/linux-acpi/56f94776-484f-48c0-8855-dba8e6a7793b@yandex.ru/T/
+Link: https://github.com/acpica/acpica/commit/2802af72
+Signed-off-by: Armin Wolf <W_Armin@gmx.de>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/psargs.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
+index 422c074ed2897..7debfd5ce0d86 100644
+--- a/drivers/acpi/acpica/psargs.c
++++ b/drivers/acpi/acpica/psargs.c
+@@ -820,6 +820,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+                           acpi_ps_get_next_namepath(walk_state, parser_state,
+                                                     arg,
+                                                     ACPI_NOT_METHOD_CALL);
++                      if (ACPI_FAILURE(status)) {
++                              acpi_ps_free_op(arg);
++                              return_ACPI_STATUS(status);
++                      }
+               } else {
+                       /* Single complex argument, nothing returned */
+@@ -854,6 +858,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+                           acpi_ps_get_next_namepath(walk_state, parser_state,
+                                                     arg,
+                                                     ACPI_POSSIBLE_METHOD_CALL);
++                      if (ACPI_FAILURE(status)) {
++                              acpi_ps_free_op(arg);
++                              return_ACPI_STATUS(status);
++                      }
+                       if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/acpica-iasl-handle-empty-connection_node.patch b/queue-6.10/acpica-iasl-handle-empty-connection_node.patch
new file mode 100644 (file)
index 0000000..493ca7a
--- /dev/null
@@ -0,0 +1,36 @@
+From 8d31bfb08347557b6f35c81e0321ac81209bc1f9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Aug 2024 23:33:44 +0200
+Subject: ACPICA: iasl: handle empty connection_node
+
+From: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
+
+[ Upstream commit a0a2459b79414584af6c46dd8c6f866d8f1aa421 ]
+
+ACPICA commit 6c551e2c9487067d4b085333e7fe97e965a11625
+
+Link: https://github.com/acpica/acpica/commit/6c551e2c
+Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@gmail.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/acpi/acpica/exprep.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
+index 08196fa17080e..82b1fa2d201fe 100644
+--- a/drivers/acpi/acpica/exprep.c
++++ b/drivers/acpi/acpica/exprep.c
+@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
+               if (info->connection_node) {
+                       second_desc = info->connection_node->object;
++                      if (second_desc == NULL) {
++                              break;
++                      }
+                       if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
+                               status =
+                                   acpi_ds_get_buffer_arguments(second_desc);
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-asihpi-fix-potential-oob-array-access.patch b/queue-6.10/alsa-asihpi-fix-potential-oob-array-access.patch
new file mode 100644 (file)
index 0000000..3bfbe49
--- /dev/null
@@ -0,0 +1,39 @@
+From 6e53134a0222a3ea9a9f849421ac8bf6c2f65abe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 11:14:42 +0200
+Subject: ALSA: asihpi: Fix potential OOB array access
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 7b986c7430a6bb68d523dac7bfc74cbd5b44ef96 ]
+
+ASIHPI driver stores some values in the static array upon a response
+from the driver, and its index depends on the firmware.  We shouldn't
+trust it blindly.
+
+This patch adds a sanity check of the array index to fit in the array
+size.
+
+Link: https://patch.msgid.link/20240808091454.30846-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/asihpi/hpimsgx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
+index d0caef2994818..b68e6bfbbfbab 100644
+--- a/sound/pci/asihpi/hpimsgx.c
++++ b/sound/pci/asihpi/hpimsgx.c
+@@ -708,7 +708,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm,
+               phr->error = HPI_ERROR_PROCESSING_MESSAGE;
+               return phr->error;
+       }
+-      if (hr.error == 0) {
++      if (hr.error == 0 && hr.u.s.adapter_index < HPI_MAX_ADAPTERS) {
+               /* the adapter was created successfully
+                  save the mapping for future use */
+               hpi_entry_points[hr.u.s.adapter_index] = entry_point_func;
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-control-take-power_ref-lock-primarily.patch b/queue-6.10/alsa-control-take-power_ref-lock-primarily.patch
new file mode 100644 (file)
index 0000000..4323633
--- /dev/null
@@ -0,0 +1,182 @@
+From 4331b02c39d70d8410d61ee148e9343fe8017cc9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 18:06:58 +0200
+Subject: ALSA: control: Take power_ref lock primarily
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit fcc62b19104a67b9a2941513771e09389b75bd95 ]
+
+The code path for kcontrol accesses have often nested locks of both
+card's controls_rwsem and power_ref, and applies in that order.
+However, what could take much longer is the latter, power_ref; it
+waits for the power state of the device, and it pretty much depends on
+the user's action.
+
+This patch swaps the locking order of those locks to a more natural
+way, namely, power_ref -> controls_rwsem, in order to shorten the time
+of possible nested locks.  For consistency, power_ref is taken always
+in the top-level caller side (that is, *_user() functions and the
+ioctl handler itself).
+
+Link: https://patch.msgid.link/20240729160659.4516-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/core/control.c | 54 ++++++++++++++++++++++++++++----------------
+ 1 file changed, 34 insertions(+), 20 deletions(-)
+
+diff --git a/sound/core/control.c b/sound/core/control.c
+index 1dd2337e29300..2151f19b432fd 100644
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -1164,9 +1164,7 @@ static int __snd_ctl_elem_info(struct snd_card *card,
+ #ifdef CONFIG_SND_DEBUG
+       info->access = 0;
+ #endif
+-      result = snd_power_ref_and_wait(card);
+-      if (!result)
+-              result = kctl->info(kctl, info);
++      result = kctl->info(kctl, info);
+       snd_power_unref(card);
+       if (result >= 0) {
+               snd_BUG_ON(info->access);
+@@ -1205,12 +1203,17 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
+ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
+                                 struct snd_ctl_elem_info __user *_info)
+ {
++      struct snd_card *card = ctl->card;
+       struct snd_ctl_elem_info info;
+       int result;
+       if (copy_from_user(&info, _info, sizeof(info)))
+               return -EFAULT;
++      result = snd_power_ref_and_wait(card);
++      if (result)
++              return result;
+       result = snd_ctl_elem_info(ctl, &info);
++      snd_power_unref(card);
+       if (result < 0)
+               return result;
+       /* drop internal access flags */
+@@ -1254,10 +1257,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
+       if (!snd_ctl_skip_validation(&info))
+               fill_remaining_elem_value(control, &info, pattern);
+-      ret = snd_power_ref_and_wait(card);
+-      if (!ret)
+-              ret = kctl->get(kctl, control);
+-      snd_power_unref(card);
++      ret = kctl->get(kctl, control);
+       if (ret < 0)
+               return ret;
+       if (!snd_ctl_skip_validation(&info) &&
+@@ -1282,7 +1282,11 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
+       if (IS_ERR(control))
+               return PTR_ERR(no_free_ptr(control));
++      result = snd_power_ref_and_wait(card);
++      if (result)
++              return result;
+       result = snd_ctl_elem_read(card, control);
++      snd_power_unref(card);
+       if (result < 0)
+               return result;
+@@ -1297,7 +1301,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_volatile *vd;
+       unsigned int index_offset;
+-      int result;
++      int result = 0;
+       down_write(&card->controls_rwsem);
+       kctl = snd_ctl_find_id_locked(card, &control->id);
+@@ -1315,9 +1319,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+       }
+       snd_ctl_build_ioff(&control->id, kctl, index_offset);
+-      result = snd_power_ref_and_wait(card);
+       /* validate input values */
+-      if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) {
++      if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION)) {
+               struct snd_ctl_elem_info info;
+               memset(&info, 0, sizeof(info));
+@@ -1329,7 +1332,6 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+       }
+       if (!result)
+               result = kctl->put(kctl, control);
+-      snd_power_unref(card);
+       if (result < 0) {
+               up_write(&card->controls_rwsem);
+               return result;
+@@ -1358,7 +1360,11 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
+               return PTR_ERR(no_free_ptr(control));
+       card = file->card;
++      result = snd_power_ref_and_wait(card);
++      if (result < 0)
++              return result;
+       result = snd_ctl_elem_write(card, file, control);
++      snd_power_unref(card);
+       if (result < 0)
+               return result;
+@@ -1827,7 +1833,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
+               {SNDRV_CTL_TLV_OP_CMD,   SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
+       };
+       struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
+-      int i, ret;
++      int i;
+       /* Check support of the request for this element. */
+       for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
+@@ -1845,11 +1851,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
+           vd->owner != NULL && vd->owner != file)
+               return -EPERM;
+-      ret = snd_power_ref_and_wait(file->card);
+-      if (!ret)
+-              ret = kctl->tlv.c(kctl, op_flag, size, buf);
+-      snd_power_unref(file->card);
+-      return ret;
++      return kctl->tlv.c(kctl, op_flag, size, buf);
+ }
+ static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
+@@ -1962,16 +1964,28 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
+       case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
+               return snd_ctl_subscribe_events(ctl, ip);
+       case SNDRV_CTL_IOCTL_TLV_READ:
+-              scoped_guard(rwsem_read, &ctl->card->controls_rwsem)
++              err = snd_power_ref_and_wait(card);
++              if (err < 0)
++                      return err;
++              scoped_guard(rwsem_read, &card->controls_rwsem)
+                       err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
++              snd_power_unref(card);
+               return err;
+       case SNDRV_CTL_IOCTL_TLV_WRITE:
+-              scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
++              err = snd_power_ref_and_wait(card);
++              if (err < 0)
++                      return err;
++              scoped_guard(rwsem_write, &card->controls_rwsem)
+                       err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
++              snd_power_unref(card);
+               return err;
+       case SNDRV_CTL_IOCTL_TLV_COMMAND:
+-              scoped_guard(rwsem_write, &ctl->card->controls_rwsem)
++              err = snd_power_ref_and_wait(card);
++              if (err < 0)
++                      return err;
++              scoped_guard(rwsem_write, &card->controls_rwsem)
+                       err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
++              snd_power_unref(card);
+               return err;
+       case SNDRV_CTL_IOCTL_POWER:
+               return -ENOPROTOOPT;
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-hdsp-break-infinite-midi-input-flush-loop.patch b/queue-6.10/alsa-hdsp-break-infinite-midi-input-flush-loop.patch
new file mode 100644 (file)
index 0000000..2d3eec5
--- /dev/null
@@ -0,0 +1,60 @@
+From 59c6dfe6c79473990fab82e1f9fd34e57548d407 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 11:15:12 +0200
+Subject: ALSA: hdsp: Break infinite MIDI input flush loop
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit c01f3815453e2d5f699ccd8c8c1f93a5b8669e59 ]
+
+The current MIDI input flush on HDSP and HDSPM drivers relies on the
+hardware reporting the right value.  If the hardware doesn't give the
+proper value but returns -1, it may be stuck at an infinite loop.
+
+Add a counter and break if the loop is unexpectedly too long.
+
+Link: https://patch.msgid.link/20240808091513.31380-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/rme9652/hdsp.c  | 6 ++++--
+ sound/pci/rme9652/hdspm.c | 6 ++++--
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
+index e7d1b43471a29..713ca262a0e97 100644
+--- a/sound/pci/rme9652/hdsp.c
++++ b/sound/pci/rme9652/hdsp.c
+@@ -1298,8 +1298,10 @@ static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id)
+ static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id)
+ {
+-      while (snd_hdsp_midi_input_available (hdsp, id))
+-              snd_hdsp_midi_read_byte (hdsp, id);
++      int count = 256;
++
++      while (snd_hdsp_midi_input_available(hdsp, id) && --count)
++              snd_hdsp_midi_read_byte(hdsp, id);
+ }
+ static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi)
+diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
+index 267c7848974ae..74215f57f4fc9 100644
+--- a/sound/pci/rme9652/hdspm.c
++++ b/sound/pci/rme9652/hdspm.c
+@@ -1838,8 +1838,10 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id)
+ static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id)
+ {
+-      while (snd_hdspm_midi_input_available (hdspm, id))
+-              snd_hdspm_midi_read_byte (hdspm, id);
++      int count = 256;
++
++      while (snd_hdspm_midi_input_available(hdspm, id) && --count)
++              snd_hdspm_midi_read_byte(hdspm, id);
+ }
+ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch b/queue-6.10/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
new file mode 100644 (file)
index 0000000..deba322
--- /dev/null
@@ -0,0 +1,140 @@
+From 183c49ca6224fed8501ca0589452922d15c7520b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 14:46:50 +0200
+Subject: ALSA: usb-audio: Add input value sanity checks for standard types
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 901e85677ec0bb9a69fb9eab1feafe0c4eb7d07e ]
+
+For an invalid input value that is out of the given range, currently
+USB-audio driver corrects the value silently and accepts without
+errors.  This is no wrong behavior, per se, but the recent kselftest
+rather wants to have an error in such a case, hence a different
+behavior is expected now.
+
+This patch adds a sanity check at each control put for the standard
+mixer types and returns an error if an invalid value is given.
+
+Note that this covers only the standard mixer types.  The mixer quirks
+that have own control callbacks would need different coverage.
+
+Link: https://patch.msgid.link/20240806124651.28203-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/mixer.c | 35 +++++++++++++++++++++++++++--------
+ sound/usb/mixer.h |  1 +
+ 2 files changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
+index 8cc2d4937f340..197fd07e69edd 100644
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -1377,6 +1377,19 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
+ #define get_min_max(cval, def)        get_min_max_with_quirks(cval, def, NULL)
++/* get the max value advertised via control API */
++static int get_max_exposed(struct usb_mixer_elem_info *cval)
++{
++      if (!cval->max_exposed) {
++              if (cval->res)
++                      cval->max_exposed =
++                              DIV_ROUND_UP(cval->max - cval->min, cval->res);
++              else
++                      cval->max_exposed = cval->max - cval->min;
++      }
++      return cval->max_exposed;
++}
++
+ /* get a feature/mixer unit info */
+ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+@@ -1389,11 +1402,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = cval->channels;
+-      if (cval->val_type == USB_MIXER_BOOLEAN ||
+-          cval->val_type == USB_MIXER_INV_BOOLEAN) {
+-              uinfo->value.integer.min = 0;
+-              uinfo->value.integer.max = 1;
+-      } else {
++      if (cval->val_type != USB_MIXER_BOOLEAN &&
++          cval->val_type != USB_MIXER_INV_BOOLEAN) {
+               if (!cval->initialized) {
+                       get_min_max_with_quirks(cval, 0, kcontrol);
+                       if (cval->initialized && cval->dBmin >= cval->dBmax) {
+@@ -1405,10 +1415,10 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
+                                              &kcontrol->id);
+                       }
+               }
+-              uinfo->value.integer.min = 0;
+-              uinfo->value.integer.max =
+-                      DIV_ROUND_UP(cval->max - cval->min, cval->res);
+       }
++
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = get_max_exposed(cval);
+       return 0;
+ }
+@@ -1449,6 +1459,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+ {
+       struct usb_mixer_elem_info *cval = kcontrol->private_data;
++      int max_val = get_max_exposed(cval);
+       int c, cnt, val, oval, err;
+       int changed = 0;
+@@ -1461,6 +1472,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
+                       if (err < 0)
+                               return filter_error(cval, err);
+                       val = ucontrol->value.integer.value[cnt];
++                      if (val < 0 || val > max_val)
++                              return -EINVAL;
+                       val = get_abs_value(cval, val);
+                       if (oval != val) {
+                               snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
+@@ -1474,6 +1487,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
+               if (err < 0)
+                       return filter_error(cval, err);
+               val = ucontrol->value.integer.value[0];
++              if (val < 0 || val > max_val)
++                      return -EINVAL;
+               val = get_abs_value(cval, val);
+               if (val != oval) {
+                       snd_usb_set_cur_mix_value(cval, 0, 0, val);
+@@ -2337,6 +2352,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
+       if (err < 0)
+               return filter_error(cval, err);
+       val = ucontrol->value.integer.value[0];
++      if (val < 0 || val > get_max_exposed(cval))
++              return -EINVAL;
+       val = get_abs_value(cval, val);
+       if (val != oval) {
+               set_cur_ctl_value(cval, cval->control << 8, val);
+@@ -2699,6 +2716,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
+       if (err < 0)
+               return filter_error(cval, err);
+       val = ucontrol->value.enumerated.item[0];
++      if (val < 0 || val >= cval->max) /* here cval->max = # elements */
++              return -EINVAL;
+       val = get_abs_value(cval, val);
+       if (val != oval) {
+               set_cur_ctl_value(cval, cval->control << 8, val);
+diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
+index d43895c1ae5c6..167fbfcf01ace 100644
+--- a/sound/usb/mixer.h
++++ b/sound/usb/mixer.h
+@@ -88,6 +88,7 @@ struct usb_mixer_elem_info {
+       int channels;
+       int val_type;
+       int min, max, res;
++      int max_exposed; /* control API exposes the value in 0..max_exposed */
+       int dBmin, dBmax;
+       int cached;
+       int cache_val[MAX_CHANNELS];
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-add-logitech-audio-profile-quirk.patch b/queue-6.10/alsa-usb-audio-add-logitech-audio-profile-quirk.patch
new file mode 100644 (file)
index 0000000..8ad6c53
--- /dev/null
@@ -0,0 +1,40 @@
+From bfdd49be2ca1e406f156915b8f69438a78b96362 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:26:28 +0000
+Subject: ALSA: usb-audio: Add logitech Audio profile quirk
+
+From: Joshua Pius <joshuapius@chromium.org>
+
+[ Upstream commit a51c925c11d7b855167e64b63eb4378e5adfc11d ]
+
+Specify shortnames for the following Logitech Devices: Rally bar, Rally
+bar mini, Tap, MeetUp and Huddle.
+
+Signed-off-by: Joshua Pius <joshuapius@chromium.org>
+Link: https://patch.msgid.link/20240912152635.1859737-1-joshuapius@google.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/card.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/sound/usb/card.c b/sound/usb/card.c
+index 778de9244f1e7..9c411b82a218d 100644
+--- a/sound/usb/card.c
++++ b/sound/usb/card.c
+@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = {
+       /* Creative/Toshiba Multimedia Center SB-0500 */
+       DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
++      /* Logitech Audio Devices */
++      DEVICE_NAME(0x046d, 0x0867, "Logitech, Inc.", "Logi-MeetUp"),
++      DEVICE_NAME(0x046d, 0x0874, "Logitech, Inc.", "Logi-Tap-Audio"),
++      DEVICE_NAME(0x046d, 0x087c, "Logitech, Inc.", "Logi-Huddle"),
++      DEVICE_NAME(0x046d, 0x0898, "Logitech, Inc.", "Logi-RB-Audio"),
++      DEVICE_NAME(0x046d, 0x08d2, "Logitech, Inc.", "Logi-RBM-Audio"),
+       DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
+       DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch b/queue-6.10/alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch
new file mode 100644 (file)
index 0000000..08d34f8
--- /dev/null
@@ -0,0 +1,482 @@
+From de5b52dd026d18af99bc8be132e464dba5c4a716 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 19:52:30 +0900
+Subject: ALSA: usb-audio: Add mixer quirk for RME Digiface USB
+
+From: Asahi Lina <lina@asahilina.net>
+
+[ Upstream commit 611a96f6acf2e74fe28cb90908a9c183862348ce ]
+
+Implement sync, output format, and input status mixer controls, to allow
+the interface to be used as a straight ADAT/SPDIF (+ Headphones) I/O
+interface.
+
+This does not implement the matrix mixer, output gain controls, or input
+level meter feedback. The full mixer interface is only really usable
+using a dedicated userspace control app (there are too many mixer nodes
+for alsamixer to be usable), so for now we leave it up to userspace to
+directly control these features using raw USB control messages. This is
+similar to how it's done with some FireWire interfaces (ffado-mixer).
+
+Signed-off-by: Asahi Lina <lina@asahilina.net>
+Link: https://patch.msgid.link/20240903-rme-digiface-v2-2-71b06c912e97@asahilina.net
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/mixer_quirks.c | 413 +++++++++++++++++++++++++++++++++++++++
+ sound/usb/quirks-table.h |   1 +
+ 2 files changed, 414 insertions(+)
+
+diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
+index 1d8bf1ecfed44..3727dbd123597 100644
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -14,6 +14,7 @@
+  *        Przemek Rudy (prudy1@o2.pl)
+  */
++#include <linux/bitfield.h>
+ #include <linux/hid.h>
+ #include <linux/init.h>
+ #include <linux/math64.h>
+@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
+       return 0;
+ }
++/*
++ * RME Digiface USB
++ */
++
++#define RME_DIGIFACE_READ_STATUS 17
++#define RME_DIGIFACE_STATUS_REG0L 0
++#define RME_DIGIFACE_STATUS_REG0H 1
++#define RME_DIGIFACE_STATUS_REG1L 2
++#define RME_DIGIFACE_STATUS_REG1H 3
++#define RME_DIGIFACE_STATUS_REG2L 4
++#define RME_DIGIFACE_STATUS_REG2H 5
++#define RME_DIGIFACE_STATUS_REG3L 6
++#define RME_DIGIFACE_STATUS_REG3H 7
++
++#define RME_DIGIFACE_CTL_REG1 16
++#define RME_DIGIFACE_CTL_REG2 18
++
++/* Reg is overloaded, 0-7 for status halfwords or 16 or 18 for control registers */
++#define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask))
++#define RME_DIGIFACE_INVERT BIT(31)
++
++/* Nonconst helpers */
++#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
++#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
++
++static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val)
++{
++      struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
++      struct snd_usb_audio *chip = list->mixer->chip;
++      struct usb_device *dev = chip->dev;
++      int err;
++
++      err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++                            item,
++                            USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++                            val, mask, NULL, 0);
++      if (err < 0)
++              dev_err(&dev->dev,
++                      "unable to issue control set request %d (ret = %d)",
++                      item, err);
++      return err;
++}
++
++static int snd_rme_digiface_read_status(struct snd_kcontrol *kcontrol, u32 status[4])
++{
++      struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
++      struct snd_usb_audio *chip = list->mixer->chip;
++      struct usb_device *dev = chip->dev;
++      __le32 buf[4];
++      int err;
++
++      err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
++                            RME_DIGIFACE_READ_STATUS,
++                            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++                            0, 0,
++                            buf, sizeof(buf));
++      if (err < 0) {
++              dev_err(&dev->dev,
++                      "unable to issue status read request (ret = %d)",
++                      err);
++      } else {
++              for (int i = 0; i < ARRAY_SIZE(buf); i++)
++                      status[i] = le32_to_cpu(buf[i]);
++      }
++      return err;
++}
++
++static int snd_rme_digiface_get_status_val(struct snd_kcontrol *kcontrol)
++{
++      int err;
++      u32 status[4];
++      bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT;
++      u8 reg = (kcontrol->private_value >> 16) & 0xff;
++      u16 mask = kcontrol->private_value & 0xffff;
++      u16 val;
++
++      err = snd_rme_digiface_read_status(kcontrol, status);
++      if (err < 0)
++              return err;
++
++      switch (reg) {
++      /* Status register halfwords */
++      case RME_DIGIFACE_STATUS_REG0L ... RME_DIGIFACE_STATUS_REG3H:
++              break;
++      case RME_DIGIFACE_CTL_REG1: /* Control register 1, present in halfword 3L */
++              reg = RME_DIGIFACE_STATUS_REG3L;
++              break;
++      case RME_DIGIFACE_CTL_REG2: /* Control register 2, present in halfword 3H */
++              reg = RME_DIGIFACE_STATUS_REG3H;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      if (reg & 1)
++              val = status[reg >> 1] >> 16;
++      else
++              val = status[reg >> 1] & 0xffff;
++
++      if (invert)
++              val ^= mask;
++
++      return field_get(mask, val);
++}
++
++static int snd_rme_digiface_rate_get(struct snd_kcontrol *kcontrol,
++                                   struct snd_ctl_elem_value *ucontrol)
++{
++      int freq = snd_rme_digiface_get_status_val(kcontrol);
++
++      if (freq < 0)
++              return freq;
++      if (freq >= ARRAY_SIZE(snd_rme_rate_table))
++              return -EIO;
++
++      ucontrol->value.integer.value[0] = snd_rme_rate_table[freq];
++      return 0;
++}
++
++static int snd_rme_digiface_enum_get(struct snd_kcontrol *kcontrol,
++                                   struct snd_ctl_elem_value *ucontrol)
++{
++      int val = snd_rme_digiface_get_status_val(kcontrol);
++
++      if (val < 0)
++              return val;
++
++      ucontrol->value.enumerated.item[0] = val;
++      return 0;
++}
++
++static int snd_rme_digiface_enum_put(struct snd_kcontrol *kcontrol,
++                                   struct snd_ctl_elem_value *ucontrol)
++{
++      bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT;
++      u8 reg = (kcontrol->private_value >> 16) & 0xff;
++      u16 mask = kcontrol->private_value & 0xffff;
++      u16 val = field_prep(mask, ucontrol->value.enumerated.item[0]);
++
++      if (invert)
++              val ^= mask;
++
++      return snd_rme_digiface_write_reg(kcontrol, reg, mask, val);
++}
++
++static int snd_rme_digiface_current_sync_get(struct snd_kcontrol *kcontrol,
++                                   struct snd_ctl_elem_value *ucontrol)
++{
++      int ret = snd_rme_digiface_enum_get(kcontrol, ucontrol);
++
++      /* 7 means internal for current sync */
++      if (ucontrol->value.enumerated.item[0] == 7)
++              ucontrol->value.enumerated.item[0] = 0;
++
++      return ret;
++}
++
++static int snd_rme_digiface_sync_state_get(struct snd_kcontrol *kcontrol,
++                                         struct snd_ctl_elem_value *ucontrol)
++{
++      u32 status[4];
++      int err;
++      bool valid, sync;
++
++      err = snd_rme_digiface_read_status(kcontrol, status);
++      if (err < 0)
++              return err;
++
++      valid = status[0] & BIT(kcontrol->private_value);
++      sync = status[0] & BIT(5 + kcontrol->private_value);
++
++      if (!valid)
++              ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_NOLOCK;
++      else if (!sync)
++              ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_LOCK;
++      else
++              ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_SYNC;
++      return 0;
++}
++
++
++static int snd_rme_digiface_format_info(struct snd_kcontrol *kcontrol,
++                                      struct snd_ctl_elem_info *uinfo)
++{
++      static const char *const format[] = {
++              "ADAT", "S/PDIF"
++      };
++
++      return snd_ctl_enum_info(uinfo, 1,
++                               ARRAY_SIZE(format), format);
++}
++
++
++static int snd_rme_digiface_sync_source_info(struct snd_kcontrol *kcontrol,
++                                           struct snd_ctl_elem_info *uinfo)
++{
++      static const char *const sync_sources[] = {
++              "Internal", "Input 1", "Input 2", "Input 3", "Input 4"
++      };
++
++      return snd_ctl_enum_info(uinfo, 1,
++                               ARRAY_SIZE(sync_sources), sync_sources);
++}
++
++static int snd_rme_digiface_rate_info(struct snd_kcontrol *kcontrol,
++                                    struct snd_ctl_elem_info *uinfo)
++{
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++      uinfo->count = 1;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = 200000;
++      uinfo->value.integer.step = 0;
++      return 0;
++}
++
++static const struct snd_kcontrol_new snd_rme_digiface_controls[] = {
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 1 Sync",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_sync_state_info,
++              .get = snd_rme_digiface_sync_state_get,
++              .private_value = 0,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 1 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0H, BIT(0)) |
++                      RME_DIGIFACE_INVERT,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 1 Rate",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_rate_info,
++              .get = snd_rme_digiface_rate_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 2 Sync",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_sync_state_info,
++              .get = snd_rme_digiface_sync_state_get,
++              .private_value = 1,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 2 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(13)) |
++                      RME_DIGIFACE_INVERT,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 2 Rate",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_rate_info,
++              .get = snd_rme_digiface_rate_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(7, 4)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 3 Sync",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_sync_state_info,
++              .get = snd_rme_digiface_sync_state_get,
++              .private_value = 2,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 3 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(14)) |
++                      RME_DIGIFACE_INVERT,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 3 Rate",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_rate_info,
++              .get = snd_rme_digiface_rate_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(11, 8)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 4 Sync",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_sync_state_info,
++              .get = snd_rme_digiface_sync_state_get,
++              .private_value = 3,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 4 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(15, 12)) |
++                      RME_DIGIFACE_INVERT,
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Input 4 Rate",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_rate_info,
++              .get = snd_rme_digiface_rate_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Output 1 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .put = snd_rme_digiface_enum_put,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(0)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Output 2 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .put = snd_rme_digiface_enum_put,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(1)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Output 3 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .put = snd_rme_digiface_enum_put,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(3)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Output 4 Format",
++              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++              .info = snd_rme_digiface_format_info,
++              .get = snd_rme_digiface_enum_get,
++              .put = snd_rme_digiface_enum_put,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(4)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Sync Source",
++              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
++              .info = snd_rme_digiface_sync_source_info,
++              .get = snd_rme_digiface_enum_get,
++              .put = snd_rme_digiface_enum_put,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(2, 0)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Current Sync Source",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_digiface_sync_source_info,
++              .get = snd_rme_digiface_current_sync_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(12, 10)),
++      },
++      {
++              /*
++               * This is writeable, but it is only set by the PCM rate.
++               * Mixer apps currently need to drive the mixer using raw USB requests,
++               * so they can also change this that way to configure the rate for
++               * stand-alone operation when the PCM is closed.
++               */
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "System Rate",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_rate_info,
++              .get = snd_rme_digiface_rate_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(6, 3)),
++      },
++      {
++              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++              .name = "Current Rate",
++              .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++              .info = snd_rme_rate_info,
++              .get = snd_rme_digiface_rate_get,
++              .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1H, GENMASK(7, 4)),
++      }
++};
++
++static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer)
++{
++      int err, i;
++
++      for (i = 0; i < ARRAY_SIZE(snd_rme_digiface_controls); ++i) {
++              err = add_single_ctl_with_resume(mixer, 0,
++                                               NULL,
++                                               &snd_rme_digiface_controls[i],
++                                               NULL);
++              if (err < 0)
++                      return err;
++      }
++
++      return 0;
++}
++
+ /*
+  * Pioneer DJ DJM Mixers
+  *
+@@ -3484,6 +3894,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
+       case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
+               err = snd_bbfpro_controls_create(mixer);
+               break;
++      case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
++              err = snd_rme_digiface_controls_create(mixer);
++              break;
+       case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
+               err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
+               break;
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index 631b9ab80f6cd..24c981c9b2405 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -3620,6 +3620,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                        * Three modes depending on sample rate band,
+                        * with different channel counts for in/out
+                        */
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+                               QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch b/queue-6.10/alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch
new file mode 100644 (file)
index 0000000..5b36fbf
--- /dev/null
@@ -0,0 +1,299 @@
+From 0143f91d92e77cf7132c159380e7ff756b555bf0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 19:52:29 +0900
+Subject: ALSA: usb-audio: Add quirk for RME Digiface USB
+
+From: Cyan Nyan <cyan.vtb@gmail.com>
+
+[ Upstream commit c032044e9672408c534d64a6df2b1ba14449e948 ]
+
+Add trivial support for audio streaming on the RME Digiface USB. Binds
+only to the first interface to allow userspace to directly drive the
+complex I/O and matrix mixer controls.
+
+Signed-off-by: Cyan Nyan <cyan.vtb@gmail.com>
+[Lina: Added 2x/4x sample rate support & boot/format quirks]
+Co-developed-by: Asahi Lina <lina@asahilina.net>
+Signed-off-by: Asahi Lina <lina@asahilina.net>
+Link: https://patch.msgid.link/20240903-rme-digiface-v2-1-71b06c912e97@asahilina.net
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks-table.h | 171 ++++++++++++++++++++++++++++++++++++++-
+ sound/usb/quirks.c       |  58 +++++++++++++
+ 2 files changed, 228 insertions(+), 1 deletion(-)
+
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index 8d22de8bc2a96..631b9ab80f6cd 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -3604,6 +3604,175 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+               }
+       }
+ },
+-
++{
++      /* Only claim interface 0 */
++      .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
++                     USB_DEVICE_ID_MATCH_PRODUCT |
++                     USB_DEVICE_ID_MATCH_INT_CLASS |
++                     USB_DEVICE_ID_MATCH_INT_NUMBER,
++      .idVendor = 0x2a39,
++      .idProduct = 0x3f8c,
++      .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
++      .bInterfaceNumber = 0,
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      /*
++                       * Three modes depending on sample rate band,
++                       * with different channel counts for in/out
++                       */
++                      {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
++                                      .formats = SNDRV_PCM_FMTBIT_S32_LE,
++                                      .channels = 34, // outputs
++                                      .fmt_bits = 24,
++                                      .iface = 0,
++                                      .altsetting = 1,
++                                      .altset_idx = 1,
++                                      .endpoint = 0x02,
++                                      .ep_idx = 1,
++                                      .ep_attr = USB_ENDPOINT_XFER_ISOC |
++                                              USB_ENDPOINT_SYNC_ASYNC,
++                                      .rates = SNDRV_PCM_RATE_32000 |
++                                              SNDRV_PCM_RATE_44100 |
++                                              SNDRV_PCM_RATE_48000,
++                                      .rate_min = 32000,
++                                      .rate_max = 48000,
++                                      .nr_rates = 3,
++                                      .rate_table = (unsigned int[]) {
++                                              32000, 44100, 48000,
++                                      },
++                                      .sync_ep = 0x81,
++                                      .sync_iface = 0,
++                                      .sync_altsetting = 1,
++                                      .sync_ep_idx = 0,
++                                      .implicit_fb = 1,
++                              },
++                      },
++                      {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
++                                      .formats = SNDRV_PCM_FMTBIT_S32_LE,
++                                      .channels = 18, // outputs
++                                      .fmt_bits = 24,
++                                      .iface = 0,
++                                      .altsetting = 1,
++                                      .altset_idx = 1,
++                                      .endpoint = 0x02,
++                                      .ep_idx = 1,
++                                      .ep_attr = USB_ENDPOINT_XFER_ISOC |
++                                              USB_ENDPOINT_SYNC_ASYNC,
++                                      .rates = SNDRV_PCM_RATE_64000 |
++                                              SNDRV_PCM_RATE_88200 |
++                                              SNDRV_PCM_RATE_96000,
++                                      .rate_min = 64000,
++                                      .rate_max = 96000,
++                                      .nr_rates = 3,
++                                      .rate_table = (unsigned int[]) {
++                                              64000, 88200, 96000,
++                                      },
++                                      .sync_ep = 0x81,
++                                      .sync_iface = 0,
++                                      .sync_altsetting = 1,
++                                      .sync_ep_idx = 0,
++                                      .implicit_fb = 1,
++                              },
++                      },
++                      {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
++                                      .formats = SNDRV_PCM_FMTBIT_S32_LE,
++                                      .channels = 10, // outputs
++                                      .fmt_bits = 24,
++                                      .iface = 0,
++                                      .altsetting = 1,
++                                      .altset_idx = 1,
++                                      .endpoint = 0x02,
++                                      .ep_idx = 1,
++                                      .ep_attr = USB_ENDPOINT_XFER_ISOC |
++                                              USB_ENDPOINT_SYNC_ASYNC,
++                                      .rates = SNDRV_PCM_RATE_KNOT |
++                                              SNDRV_PCM_RATE_176400 |
++                                              SNDRV_PCM_RATE_192000,
++                                      .rate_min = 128000,
++                                      .rate_max = 192000,
++                                      .nr_rates = 3,
++                                      .rate_table = (unsigned int[]) {
++                                              128000, 176400, 192000,
++                                      },
++                                      .sync_ep = 0x81,
++                                      .sync_iface = 0,
++                                      .sync_altsetting = 1,
++                                      .sync_ep_idx = 0,
++                                      .implicit_fb = 1,
++                              },
++                      },
++                      {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
++                                      .formats = SNDRV_PCM_FMTBIT_S32_LE,
++                                      .channels = 32, // inputs
++                                      .fmt_bits = 24,
++                                      .iface = 0,
++                                      .altsetting = 1,
++                                      .altset_idx = 1,
++                                      .endpoint = 0x81,
++                                      .ep_attr = USB_ENDPOINT_XFER_ISOC |
++                                              USB_ENDPOINT_SYNC_ASYNC,
++                                      .rates = SNDRV_PCM_RATE_32000 |
++                                              SNDRV_PCM_RATE_44100 |
++                                              SNDRV_PCM_RATE_48000,
++                                      .rate_min = 32000,
++                                      .rate_max = 48000,
++                                      .nr_rates = 3,
++                                      .rate_table = (unsigned int[]) {
++                                              32000, 44100, 48000,
++                                      }
++                              }
++                      },
++                      {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
++                                      .formats = SNDRV_PCM_FMTBIT_S32_LE,
++                                      .channels = 16, // inputs
++                                      .fmt_bits = 24,
++                                      .iface = 0,
++                                      .altsetting = 1,
++                                      .altset_idx = 1,
++                                      .endpoint = 0x81,
++                                      .ep_attr = USB_ENDPOINT_XFER_ISOC |
++                                              USB_ENDPOINT_SYNC_ASYNC,
++                                      .rates = SNDRV_PCM_RATE_64000 |
++                                              SNDRV_PCM_RATE_88200 |
++                                              SNDRV_PCM_RATE_96000,
++                                      .rate_min = 64000,
++                                      .rate_max = 96000,
++                                      .nr_rates = 3,
++                                      .rate_table = (unsigned int[]) {
++                                              64000, 88200, 96000,
++                                      }
++                              }
++                      },
++                      {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
++                                      .formats = SNDRV_PCM_FMTBIT_S32_LE,
++                                      .channels = 8, // inputs
++                                      .fmt_bits = 24,
++                                      .iface = 0,
++                                      .altsetting = 1,
++                                      .altset_idx = 1,
++                                      .endpoint = 0x81,
++                                      .ep_attr = USB_ENDPOINT_XFER_ISOC |
++                                              USB_ENDPOINT_SYNC_ASYNC,
++                                      .rates = SNDRV_PCM_RATE_KNOT |
++                                              SNDRV_PCM_RATE_176400 |
++                                              SNDRV_PCM_RATE_192000,
++                                      .rate_min = 128000,
++                                      .rate_max = 192000,
++                                      .nr_rates = 3,
++                                      .rate_table = (unsigned int[]) {
++                                              128000, 176400, 192000,
++                                      }
++                              }
++                      },
++                      QUIRK_COMPOSITE_END
++              }
++      }
++},
+ #undef USB_DEVICE_VENDOR_SPEC
+ #undef USB_AUDIO_DEVICE
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index e7b68c67852e9..73da862a012c6 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -1389,6 +1389,27 @@ static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
+       return 0;
+ }
++static int snd_usb_rme_digiface_boot_quirk(struct usb_device *dev)
++{
++      /* Disable mixer, internal clock, all outputs ADAT, 48kHz, TMS off */
++      snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++                      16, 0x40, 0x2410, 0x7fff, NULL, 0);
++      snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++                      18, 0x40, 0x0104, 0xffff, NULL, 0);
++
++      /* Disable loopback for all inputs */
++      for (int ch = 0; ch < 32; ch++)
++              snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++                              22, 0x40, 0x400, ch, NULL, 0);
++
++      /* Unity gain for all outputs */
++      for (int ch = 0; ch < 34; ch++)
++              snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
++                              21, 0x40, 0x9000, 0x100 + ch, NULL, 0);
++
++      return 0;
++}
++
+ /*
+  * Setup quirks
+  */
+@@ -1616,6 +1637,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
+                   get_iface_desc(intf->altsetting)->bInterfaceNumber < 3)
+                       return snd_usb_motu_microbookii_boot_quirk(dev);
+               break;
++      case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
++              return snd_usb_rme_digiface_boot_quirk(dev);
+       }
+       return 0;
+@@ -1771,6 +1794,38 @@ static void mbox3_set_format_quirk(struct snd_usb_substream *subs,
+               dev_warn(&subs->dev->dev, "MBOX3: Couldn't set the sample rate");
+ }
++static const int rme_digiface_rate_table[] = {
++      32000, 44100, 48000, 0,
++      64000, 88200, 96000, 0,
++      128000, 176400, 192000, 0,
++};
++
++static int rme_digiface_set_format_quirk(struct snd_usb_substream *subs)
++{
++      unsigned int cur_rate = subs->data_endpoint->cur_rate;
++      u16 val;
++      int speed_mode;
++      int id;
++
++      for (id = 0; id < ARRAY_SIZE(rme_digiface_rate_table); id++) {
++              if (rme_digiface_rate_table[id] == cur_rate)
++                      break;
++      }
++
++      if (id >= ARRAY_SIZE(rme_digiface_rate_table))
++              return -EINVAL;
++
++      /* 2, 3, 4 for 1x, 2x, 4x */
++      speed_mode = (id >> 2) + 2;
++      val = (id << 3) | (speed_mode << 12);
++
++      /* Set the sample rate */
++      snd_usb_ctl_msg(subs->stream->chip->dev,
++              usb_sndctrlpipe(subs->stream->chip->dev, 0),
++              16, 0x40, val, 0x7078, NULL, 0);
++      return 0;
++}
++
+ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
+                             const struct audioformat *fmt)
+ {
+@@ -1795,6 +1850,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
+       case USB_ID(0x0dba, 0x5000):
+               mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */
+               break;
++      case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
++              rme_digiface_set_format_quirk(subs);
++              break;
+       }
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-define-macros-for-quirk-table-entries.patch b/queue-6.10/alsa-usb-audio-define-macros-for-quirk-table-entries.patch
new file mode 100644 (file)
index 0000000..a8f4f53
--- /dev/null
@@ -0,0 +1,111 @@
+From f10c85ec1807c1cdb4f9e04fb650aa8f14fbbca0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Aug 2024 15:48:41 +0200
+Subject: ALSA: usb-audio: Define macros for quirk table entries
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 0c3ad39b791c2ecf718afcaca30e5ceafa939d5c ]
+
+Many entries in the USB-audio quirk tables have relatively complex
+expressions.  For improving the readability, introduce a few macros.
+Those are applied in the following patch.
+
+Link: https://patch.msgid.link/20240814134844.2726-2-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks-table.h | 77 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 77 insertions(+)
+
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index aaa6a515d0f8a..e3a25f4f68792 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -35,6 +35,83 @@
+       .bInterfaceClass = USB_CLASS_AUDIO, \
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL
++/* Quirk .driver_info, followed by the definition of the quirk entry;
++ * put like QUIRK_DRIVER_INFO { ... } in each entry of the quirk table
++ */
++#define QUIRK_DRIVER_INFO \
++      .driver_info = (unsigned long)&(const struct snd_usb_audio_quirk)
++
++/*
++ * Macros for quirk data entries
++ */
++
++/* Quirk data entry for ignoring the interface */
++#define QUIRK_DATA_IGNORE(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_IGNORE_INTERFACE
++/* Quirk data entry for a standard audio interface */
++#define QUIRK_DATA_STANDARD_AUDIO(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_INTERFACE
++/* Quirk data entry for a standard MIDI interface */
++#define QUIRK_DATA_STANDARD_MIDI(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_MIDI_STANDARD_INTERFACE
++/* Quirk data entry for a standard mixer interface */
++#define QUIRK_DATA_STANDARD_MIXER(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_MIXER
++
++/* Quirk data entry for Yamaha MIDI */
++#define QUIRK_DATA_MIDI_YAMAHA(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_MIDI_YAMAHA
++/* Quirk data entry for Edirol UAxx */
++#define QUIRK_DATA_EDIROL_UAXX(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_AUDIO_EDIROL_UAXX
++/* Quirk data entry for raw bytes interface */
++#define QUIRK_DATA_RAW_BYTES(_ifno) \
++      .ifnum = (_ifno), .type = QUIRK_MIDI_RAW_BYTES
++
++/* Quirk composite array terminator */
++#define QUIRK_COMPOSITE_END   { .ifnum = -1 }
++
++/* Quirk data entry for composite quirks;
++ * followed by the quirk array that is terminated with QUIRK_COMPOSITE_END
++ * e.g. QUIRK_DATA_COMPOSITE { { quirk1 }, { quirk2 },..., QUIRK_COMPOSITE_END }
++ */
++#define QUIRK_DATA_COMPOSITE \
++      .ifnum = QUIRK_ANY_INTERFACE, \
++      .type = QUIRK_COMPOSITE, \
++      .data = &(const struct snd_usb_audio_quirk[])
++
++/* Quirk data entry for a fixed audio endpoint;
++ * followed by audioformat definition
++ * e.g. QUIRK_DATA_AUDIOFORMAT(n) { .formats = xxx, ... }
++ */
++#define QUIRK_DATA_AUDIOFORMAT(_ifno)     \
++      .ifnum = (_ifno),                   \
++      .type = QUIRK_AUDIO_FIXED_ENDPOINT, \
++      .data = &(const struct audioformat)
++
++/* Quirk data entry for a fixed MIDI endpoint;
++ * followed by snd_usb_midi_endpoint_info definition
++ * e.g. QUIRK_DATA_MIDI_FIXED_ENDPOINT(n) { .out_cables = x, .in_cables = y }
++ */
++#define QUIRK_DATA_MIDI_FIXED_ENDPOINT(_ifno) \
++      .ifnum = (_ifno),                     \
++      .type = QUIRK_MIDI_FIXED_ENDPOINT,    \
++      .data = &(const struct snd_usb_midi_endpoint_info)
++/* Quirk data entry for a MIDIMAN MIDI endpoint */
++#define QUIRK_DATA_MIDI_MIDIMAN(_ifno) \
++      .ifnum = (_ifno),              \
++      .type = QUIRK_MIDI_MIDIMAN,    \
++      .data = &(const struct snd_usb_midi_endpoint_info)
++/* Quirk data entry for a EMAGIC MIDI endpoint */
++#define QUIRK_DATA_MIDI_EMAGIC(_ifno) \
++      .ifnum = (_ifno),             \
++      .type = QUIRK_MIDI_EMAGIC,    \
++      .data = &(const struct snd_usb_midi_endpoint_info)
++
++/*
++ * Here we go... the quirk table definition begins:
++ */
++
+ /* FTDI devices */
+ {
+       USB_DEVICE(0x0403, 0xb8d8),
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch b/queue-6.10/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
new file mode 100644 (file)
index 0000000..547da88
--- /dev/null
@@ -0,0 +1,4000 @@
+From c6df1184fbe038fcae1a393857c9bdab1fd95cf9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Aug 2024 15:48:42 +0200
+Subject: ALSA: usb-audio: Replace complex quirk lines with macros
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit d79e13f8e8abb5cd3a2a0f9fc9bc3fc750c5b06f ]
+
+Apply the newly introduced macros for reduce the complex expressions
+and cast in the quirk table definitions.  It results in a significant
+code reduction, too.
+
+There should be no functional changes.
+
+Link: https://patch.msgid.link/20240814134844.2726-3-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/quirks-table.h | 2210 ++++++++++----------------------------
+ 1 file changed, 593 insertions(+), 1617 deletions(-)
+
+diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
+index e3a25f4f68792..8d22de8bc2a96 100644
+--- a/sound/usb/quirks-table.h
++++ b/sound/usb/quirks-table.h
+@@ -115,7 +115,7 @@
+ /* FTDI devices */
+ {
+       USB_DEVICE(0x0403, 0xb8d8),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "STARR LABS", */
+               /* .product_name = "Starr Labs MIDI USB device", */
+               .ifnum = 0,
+@@ -126,10 +126,8 @@
+ {
+       /* Creative BT-D1 */
+       USB_DEVICE(0x041e, 0x0005),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = 1,
+-              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-              .data = &(const struct audioformat) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_AUDIOFORMAT(1) {
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .channels = 2,
+                       .iface = 1,
+@@ -164,18 +162,11 @@
+  */
+ {
+       USB_AUDIO_DEVICE(0x041e, 0x4095),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(2) },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(3) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 16,
+@@ -191,9 +182,7 @@
+                                       .rate_table = (unsigned int[]) { 48000 },
+                               },
+                       },
+-                      {
+-                              .ifnum = -1
+-                      },
++                      QUIRK_COMPOSITE_END
+               },
+       },
+ },
+@@ -205,31 +194,18 @@
+  */
+ {
+       USB_DEVICE(0x0424, 0xb832),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Standard Microsystems Corp.",
+               .product_name = "HP Wireless Audio",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       /* Mixer */
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE,
+-                      },
++                      { QUIRK_DATA_IGNORE(0) },
+                       /* Playback */
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE,
+-                      },
++                      { QUIRK_DATA_IGNORE(1) },
+                       /* Capture */
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_IGNORE_INTERFACE,
+-                      },
++                      { QUIRK_DATA_IGNORE(2) },
+                       /* HID Device, .ifnum = 3 */
+-                      {
+-                              .ifnum = -1,
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -252,20 +228,18 @@
+ #define YAMAHA_DEVICE(id, name) { \
+       USB_DEVICE(0x0499, id), \
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
++      QUIRK_DRIVER_INFO { \
+               .vendor_name = "Yamaha", \
+               .product_name = name, \
+-              .ifnum = QUIRK_ANY_INTERFACE, \
+-              .type = QUIRK_MIDI_YAMAHA \
++              QUIRK_DATA_MIDI_YAMAHA(QUIRK_ANY_INTERFACE) \
+       } \
+ }
+ #define YAMAHA_INTERFACE(id, intf, name) { \
+       USB_DEVICE_VENDOR_SPEC(0x0499, id), \
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \
++      QUIRK_DRIVER_INFO { \
+               .vendor_name = "Yamaha", \
+               .product_name = name, \
+-              .ifnum = intf, \
+-              .type = QUIRK_MIDI_YAMAHA \
++              QUIRK_DATA_MIDI_YAMAHA(intf) \
+       } \
+ }
+ YAMAHA_DEVICE(0x1000, "UX256"),
+@@ -353,135 +327,67 @@ YAMAHA_DEVICE(0x105d, NULL),
+ YAMAHA_DEVICE(0x1718, "P-125"),
+ {
+       USB_DEVICE(0x0499, 0x1503),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Yamaha", */
+               /* .product_name = "MOX6/MOX8", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_YAMAHA
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      { QUIRK_DATA_MIDI_YAMAHA(3) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0499, 0x1507),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Yamaha", */
+               /* .product_name = "THR10", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_YAMAHA
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      { QUIRK_DATA_MIDI_YAMAHA(3) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0499, 0x1509),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Yamaha", */
+               /* .product_name = "Steinberg UR22", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_YAMAHA
+-                      },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      { QUIRK_DATA_MIDI_YAMAHA(3) },
++                      { QUIRK_DATA_IGNORE(4) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0499, 0x150a),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Yamaha", */
+               /* .product_name = "THR5A", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_YAMAHA
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      { QUIRK_DATA_MIDI_YAMAHA(3) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0499, 0x150c),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Yamaha", */
+               /* .product_name = "THR10C", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_YAMAHA
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      { QUIRK_DATA_MIDI_YAMAHA(3) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -515,7 +421,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                      USB_DEVICE_ID_MATCH_INT_CLASS,
+       .idVendor = 0x0499,
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUTODETECT
+       }
+@@ -526,16 +432,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+  */
+ {
+       USB_DEVICE(0x0582, 0x0000),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "UA-100",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 4,
+                                       .iface = 0,
+@@ -550,9 +452,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 1,
+@@ -567,106 +467,66 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0007,
+                                       .in_cables  = 0x0007
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0002),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UM-4",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x000f,
+                                       .in_cables  = 0x000f
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0003),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "SC-8850",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x003f,
+                                       .in_cables  = 0x003f
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0004),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "U-8",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0005,
+                                       .in_cables  = 0x0005
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -674,152 +534,92 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+       /* Has ID 0x0099 when not in "Advanced Driver" mode.
+        * The UM-2EX has only one input, but we cannot detect this. */
+       USB_DEVICE(0x0582, 0x0005),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UM-2",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0003,
+                                       .in_cables  = 0x0003
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0007),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "SC-8820",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0013,
+                                       .in_cables  = 0x0013
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0008),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "PC-300",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x009d when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0009),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UM-1",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x000b),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "SK-500",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0013,
+                                       .in_cables  = 0x0013
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -827,31 +627,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+       /* thanks to Emiliano Grilli <emillo@libero.it>
+        * for helping researching this data */
+       USB_DEVICE(0x0582, 0x000c),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "SC-D70",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0007,
+                                       .in_cables  = 0x0007
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -865,35 +653,23 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * the 96kHz sample rate.
+        */
+       USB_DEVICE(0x0582, 0x0010),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-5",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x0013 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0012),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "XV-5050",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -902,12 +678,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0015 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0014),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UM-880",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x01ff,
+                       .in_cables  = 0x01ff
+               }
+@@ -916,74 +690,48 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0017 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0016),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "SD-90",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x000f,
+                                       .in_cables  = 0x000f
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x001c when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x001b),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "MMP-2",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x001e when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x001d),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "V-SYNTH",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -992,12 +740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0024 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0023),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UM-550",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x003f,
+                       .in_cables  = 0x003f
+               }
+@@ -1010,20 +756,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * and no MIDI.
+        */
+       USB_DEVICE(0x0582, 0x0025),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-20",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 2,
+                                       .iface = 1,
+@@ -1038,9 +777,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 2,
+                                       .iface = 2,
+@@ -1055,28 +792,22 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x0028 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0027),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "SD-20",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0007
+               }
+@@ -1085,12 +816,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x002a when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0029),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "SD-80",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x000f,
+                       .in_cables  = 0x000f
+               }
+@@ -1103,39 +832,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * but offers only 16-bit PCM and no MIDI.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-700",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_EDIROL_UAXX(1) },
++                      { QUIRK_DATA_EDIROL_UAXX(2) },
++                      { QUIRK_DATA_EDIROL_UAXX(3) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x002e when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x002d),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "XV-2020",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1144,12 +858,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0030 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x002f),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "VariOS",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0007,
+                       .in_cables  = 0x0007
+               }
+@@ -1158,12 +870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0034 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0033),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "PCR",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0007
+               }
+@@ -1175,12 +885,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * later revisions use IDs 0x0054 and 0x00a2.
+        */
+       USB_DEVICE(0x0582, 0x0037),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "Digital Piano",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1193,39 +901,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * and no MIDI.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "BOSS",
+               .product_name = "GS-10",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      { QUIRK_DATA_STANDARD_MIDI(3) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x0041 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0040),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "GI-20",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1234,12 +927,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0043 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0042),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "RS-70",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1248,36 +939,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0049 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0047),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "UR-80", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       /* in the 96 kHz modes, only interface 1 is there */
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x004a when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0048),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "UR-80", */
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0007
+               }
+@@ -1286,35 +965,23 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x004e when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x004c),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "PCR-A",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x004f when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x004d),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "PCR-A",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0007
+               }
+@@ -1326,76 +993,52 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * is standard compliant, but has only 16-bit PCM.
+        */
+       USB_DEVICE(0x0582, 0x0050),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-3FX",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0052),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UM-1SX",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE
++              QUIRK_DATA_STANDARD_MIDI(0)
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0060),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "EXR Series",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE
++              QUIRK_DATA_STANDARD_MIDI(0)
+       }
+ },
+ {
+       /* has ID 0x0066 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0064),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "PCR-1", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x0067 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0065),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "PCR-1", */
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0003
+               }
+@@ -1404,12 +1047,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x006e when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x006d),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "FANTOM-X",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1422,39 +1063,24 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * offers only 16-bit PCM at 44.1 kHz and no MIDI.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x0074),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-25",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_EDIROL_UAXX(0) },
++                      { QUIRK_DATA_EDIROL_UAXX(1) },
++                      { QUIRK_DATA_EDIROL_UAXX(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* has ID 0x0076 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0075),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "BOSS",
+               .product_name = "DR-880",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1463,12 +1089,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x007b when not in "Advanced Driver" mode */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x007a),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               /* "RD" or "RD-700SX"? */
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0003
+               }
+@@ -1477,12 +1101,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x0081 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0080),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Roland",
+               .product_name = "G-70",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1491,12 +1113,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* has ID 0x008c when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x008b),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "PC-50",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1508,56 +1128,31 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * is standard compliant, but has only 16-bit PCM and no MIDI.
+        */
+       USB_DEVICE(0x0582, 0x00a3),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-4FX",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_EDIROL_UAXX(0) },
++                      { QUIRK_DATA_EDIROL_UAXX(1) },
++                      { QUIRK_DATA_EDIROL_UAXX(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* Edirol M-16DX */
+       USB_DEVICE(0x0582, 0x00c4),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -1567,37 +1162,22 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * offers only 16-bit PCM at 44.1 kHz and no MIDI.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "EDIROL",
+               .product_name = "UA-25EX",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_EDIROL_UAXX
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_EDIROL_UAXX(0) },
++                      { QUIRK_DATA_EDIROL_UAXX(1) },
++                      { QUIRK_DATA_EDIROL_UAXX(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* Edirol UM-3G */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) {
+                       .out_cables = 0x0007,
+                       .in_cables  = 0x0007
+               }
+@@ -1606,45 +1186,29 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* BOSS ME-25 */
+       USB_DEVICE(0x0582, 0x0113),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* only 44.1 kHz works at the moment */
+       USB_DEVICE(0x0582, 0x0120),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "OCTO-CAPTURE", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 10,
+                                       .iface = 0,
+@@ -1660,9 +1224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 12,
+                                       .iface = 1,
+@@ -1678,40 +1240,26 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_IGNORE(3) },
++                      { QUIRK_DATA_IGNORE(4) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* only 44.1 kHz works at the moment */
+       USB_DEVICE(0x0582, 0x012f),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "QUAD-CAPTURE", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 4,
+                                       .iface = 0,
+@@ -1727,9 +1275,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 6,
+                                       .iface = 1,
+@@ -1745,54 +1291,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_IGNORE(3) },
++                      { QUIRK_DATA_IGNORE(4) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0582, 0x0159),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "UA-22", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) {
+                                       .out_cables = 0x0001,
+                                       .in_cables = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -1800,19 +1324,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* UA101 and co are supported by another driver */
+ {
+       USB_DEVICE(0x0582, 0x0044), /* UA-1000 high speed */
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .ifnum = QUIRK_NODEV_INTERFACE
+       },
+ },
+ {
+       USB_DEVICE(0x0582, 0x007d), /* UA-101 high speed */
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .ifnum = QUIRK_NODEV_INTERFACE
+       },
+ },
+ {
+       USB_DEVICE(0x0582, 0x008d), /* UA-101 full speed */
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .ifnum = QUIRK_NODEV_INTERFACE
+       },
+ },
+@@ -1823,7 +1347,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                      USB_DEVICE_ID_MATCH_INT_CLASS,
+       .idVendor = 0x0582,
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUTODETECT
+       }
+@@ -1838,12 +1362,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * compliant USB MIDI ports for external MIDI and controls.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x06f8, 0xb000),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Hercules",
+               .product_name = "DJ Console (WE)",
+-              .ifnum = 4,
+-              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) {
+                       .out_cables = 0x0001,
+                       .in_cables = 0x0001
+               }
+@@ -1853,12 +1375,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Midiman/M-Audio devices */
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x1002),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "MidiSport 2x2",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0003
+               }
+@@ -1866,12 +1386,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x1011),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "MidiSport 1x1",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1879,12 +1397,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x1015),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "Keystation",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -1892,12 +1408,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x1021),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "MidiSport 4x4",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x000f,
+                       .in_cables  = 0x000f
+               }
+@@ -1910,12 +1424,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * Thanks to Olaf Giesbrecht <Olaf_Giesbrecht@yahoo.de>
+        */
+       USB_DEVICE_VER(0x0763, 0x1031, 0x0100, 0x0109),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "MidiSport 8x8",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x01ff,
+                       .in_cables  = 0x01ff
+               }
+@@ -1923,12 +1435,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x1033),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "MidiSport 8x8",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x01ff,
+                       .in_cables  = 0x01ff
+               }
+@@ -1936,12 +1446,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x1041),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "MidiSport 2x4",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) {
+                       .out_cables = 0x000f,
+                       .in_cables  = 0x0003
+               }
+@@ -1949,76 +1457,41 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2001),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "Quattro",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       /*
+                        * Interfaces 0-2 are "Windows-compatible", 16-bit only,
+                        * and share endpoints with the other interfaces.
+                        * Ignore them.  The other interfaces can do 24 bits,
+                        * but captured samples are big-endian (see usbaudio.c).
+                        */
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 5,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 6,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 7,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 8,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 9,
+-                              .type = QUIRK_MIDI_MIDIMAN,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
++                      { QUIRK_DATA_IGNORE(2) },
++                      { QUIRK_DATA_IGNORE(3) },
++                      { QUIRK_DATA_STANDARD_AUDIO(4) },
++                      { QUIRK_DATA_STANDARD_AUDIO(5) },
++                      { QUIRK_DATA_IGNORE(6) },
++                      { QUIRK_DATA_STANDARD_AUDIO(7) },
++                      { QUIRK_DATA_STANDARD_AUDIO(8) },
++                      {
++                              QUIRK_DATA_MIDI_MIDIMAN(9) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2003),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "AudioPhile",
+-              .ifnum = 6,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(6) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -2026,12 +1499,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2008),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "Ozone",
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_MIDIMAN,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_MIDIMAN(3) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+@@ -2039,93 +1510,45 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x200d),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "M-Audio",
+               .product_name = "OmniStudio",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 5,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 6,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 7,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 8,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 9,
+-                              .type = QUIRK_MIDI_MIDIMAN,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
++                      { QUIRK_DATA_IGNORE(2) },
++                      { QUIRK_DATA_IGNORE(3) },
++                      { QUIRK_DATA_STANDARD_AUDIO(4) },
++                      { QUIRK_DATA_STANDARD_AUDIO(5) },
++                      { QUIRK_DATA_IGNORE(6) },
++                      { QUIRK_DATA_STANDARD_AUDIO(7) },
++                      { QUIRK_DATA_STANDARD_AUDIO(8) },
++                      {
++                              QUIRK_DATA_MIDI_MIDIMAN(9) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x0763, 0x2019),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "M-Audio", */
+               /* .product_name = "Ozone Academic", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_MIDIMAN,
+-                              .data = & (const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_MIDIMAN(3) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2135,21 +1558,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "M-Audio", */
+               /* .product_name = "Fast Track C400", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(1) },
+                       /* Playback */
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 6,
+                                       .iface = 2,
+@@ -2173,9 +1589,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                       },
+                       /* Capture */
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(3) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 3,
+@@ -2197,30 +1611,21 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .clock = 0x80,
+                               }
+                       },
+-                      /* MIDI */
+-                      {
+-                              .ifnum = -1 /* Interface = 4 */
+-                      }
++                      /* MIDI: Interface = 4*/
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2031),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "M-Audio", */
+               /* .product_name = "Fast Track C600", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(1) },
+                       /* Playback */
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+@@ -2244,9 +1649,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                       },
+                       /* Capture */
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(3) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 6,
+                                       .iface = 3,
+@@ -2268,29 +1671,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .clock = 0x80,
+                               }
+                       },
+-                      /* MIDI */
+-                      {
+-                              .ifnum = -1 /* Interface = 4 */
+-                      }
++                      /* MIDI: Interface = 4 */
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "M-Audio", */
+               /* .product_name = "Fast Track Ultra", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+@@ -2312,9 +1706,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+@@ -2336,28 +1728,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       /* interface 3 (MIDI) is standard compliant */
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "M-Audio", */
+               /* .product_name = "Fast Track Ultra 8R", */
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+@@ -2379,9 +1762,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+@@ -2403,9 +1784,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       /* interface 3 (MIDI) is standard compliant */
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2413,21 +1792,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Casio devices */
+ {
+       USB_DEVICE(0x07cf, 0x6801),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Casio",
+               .product_name = "PL-40R",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_YAMAHA
++              QUIRK_DATA_MIDI_YAMAHA(0)
+       }
+ },
+ {
+       /* this ID is used by several devices without a product ID */
+       USB_DEVICE(0x07cf, 0x6802),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Casio",
+               .product_name = "Keyboard",
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_YAMAHA
++              QUIRK_DATA_MIDI_YAMAHA(0)
+       }
+ },
+@@ -2440,23 +1817,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+       .idVendor = 0x07fd,
+       .idProduct = 0x0001,
+       .bDeviceSubClass = 2,
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "MOTU",
+               .product_name = "Fastlane",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_MIDI_RAW_BYTES
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_RAW_BYTES(0) },
++                      { QUIRK_DATA_IGNORE(1) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2464,12 +1831,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Emagic devices */
+ {
+       USB_DEVICE(0x086a, 0x0001),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Emagic",
+               .product_name = "Unitor8",
+-              .ifnum = 2,
+-              .type = QUIRK_MIDI_EMAGIC,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_EMAGIC(2) {
+                       .out_cables = 0x80ff,
+                       .in_cables  = 0x80ff
+               }
+@@ -2477,12 +1842,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE(0x086a, 0x0002),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Emagic",
+               /* .product_name = "AMT8", */
+-              .ifnum = 2,
+-              .type = QUIRK_MIDI_EMAGIC,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_EMAGIC(2) {
+                       .out_cables = 0x80ff,
+                       .in_cables  = 0x80ff
+               }
+@@ -2490,12 +1853,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE(0x086a, 0x0003),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Emagic",
+               /* .product_name = "MT4", */
+-              .ifnum = 2,
+-              .type = QUIRK_MIDI_EMAGIC,
+-              .data = & (const struct snd_usb_midi_endpoint_info) {
++              QUIRK_DATA_MIDI_EMAGIC(2) {
+                       .out_cables = 0x800f,
+                       .in_cables  = 0x8003
+               }
+@@ -2505,38 +1866,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* KORG devices */
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "KORG, Inc.",
+               /* .product_name = "PANDORA PX5D", */
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE,
++              QUIRK_DATA_STANDARD_MIDI(3)
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0944, 0x0201),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "KORG, Inc.",
+               /* .product_name = "ToneLab ST", */
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE,
++              QUIRK_DATA_STANDARD_MIDI(3)
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0944, 0x0204),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "KORG, Inc.",
+               /* .product_name = "ToneLab EX", */
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE,
++              QUIRK_DATA_STANDARD_MIDI(3)
+       }
+ },
+ /* AKAI devices */
+ {
+       USB_DEVICE(0x09e8, 0x0062),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "AKAI",
+               .product_name = "MPD16",
+               .ifnum = 0,
+@@ -2547,21 +1905,11 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* Akai MPC Element */
+       USB_DEVICE(0x09e8, 0x0021),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_MIDI_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_STANDARD_MIDI(1) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2570,66 +1918,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* Steinberg MI2 */
+       USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x2040),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = &(const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* Steinberg MI4 */
+       USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x4040),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = & (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = &(const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2637,34 +1955,31 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* TerraTec devices */
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "TerraTec",
+               .product_name = "PHASE 26",
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE
++              QUIRK_DATA_STANDARD_MIDI(3)
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "TerraTec",
+               .product_name = "PHASE 26",
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE
++              QUIRK_DATA_STANDARD_MIDI(3)
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0014),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "TerraTec",
+               .product_name = "PHASE 26",
+-              .ifnum = 3,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE
++              QUIRK_DATA_STANDARD_MIDI(3)
+       }
+ },
+ {
+       USB_DEVICE(0x0ccd, 0x0035),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Miditech",
+               .product_name = "Play'n Roll",
+               .ifnum = 0,
+@@ -2679,7 +1994,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Novation EMS devices */
+ {
+       USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Novation",
+               .product_name = "ReMOTE Audio/XStation",
+               .ifnum = 4,
+@@ -2688,7 +2003,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x1235, 0x0002),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Novation",
+               .product_name = "Speedio",
+               .ifnum = 3,
+@@ -2697,38 +2012,29 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ },
+ {
+       USB_DEVICE(0x1235, 0x000a),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Novation", */
+               /* .product_name = "Nocturn", */
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_RAW_BYTES
++              QUIRK_DATA_RAW_BYTES(0)
+       }
+ },
+ {
+       USB_DEVICE(0x1235, 0x000e),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               /* .vendor_name = "Novation", */
+               /* .product_name = "Launchpad", */
+-              .ifnum = 0,
+-              .type = QUIRK_MIDI_RAW_BYTES
++              QUIRK_DATA_RAW_BYTES(0)
+       }
+ },
+ {
+       USB_DEVICE(0x1235, 0x0010),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Focusrite",
+               .product_name = "Saffire 6 USB",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 0,
+@@ -2755,9 +2061,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 2,
+                                       .iface = 0,
+@@ -2779,28 +2083,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_MIDI_RAW_BYTES
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_RAW_BYTES(1) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE(0x1235, 0x0018),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Novation",
+               .product_name = "Twitch",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = & (const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 0,
+@@ -2819,19 +2114,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_MIDI_RAW_BYTES
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_RAW_BYTES(1) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Novation",
+               .product_name = "ReMOTE25",
+               .ifnum = 0,
+@@ -2843,25 +2133,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* VirusTI Desktop */
+       USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = &(const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) {
+                                       .out_cables = 0x0003,
+                                       .in_cables  = 0x0003
+                               }
+                       },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_IGNORE(4) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2889,7 +2170,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* QinHeng devices */
+ {
+       USB_DEVICE(0x1a86, 0x752d),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "QinHeng",
+               .product_name = "CH345",
+               .ifnum = 1,
+@@ -2903,7 +2184,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Miditech devices */
+ {
+       USB_DEVICE(0x4752, 0x0011),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Miditech",
+               .product_name = "Midistart-2",
+               .ifnum = 0,
+@@ -2915,7 +2196,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* this ID used by both Miditech MidiStudio-2 and CME UF-x */
+       USB_DEVICE(0x7104, 0x2202),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .ifnum = 0,
+               .type = QUIRK_MIDI_CME
+       }
+@@ -2925,20 +2206,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       /* Thanks to Clemens Ladisch <clemens@ladisch.de> */
+       USB_DEVICE(0x0dba, 0x1000),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Digidesign",
+               .product_name = "MBox",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]){
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE{
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 1,
+@@ -2959,9 +2233,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 1,
+@@ -2982,9 +2254,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -2992,24 +2262,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* DIGIDESIGN MBOX 2 */
+ {
+       USB_DEVICE(0x0dba, 0x3000),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Digidesign",
+               .product_name = "Mbox 2",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 2,
+@@ -3027,15 +2287,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
++                      { QUIRK_DATA_IGNORE(3) },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
+-                              .formats = SNDRV_PCM_FMTBIT_S24_3BE,
++                              QUIRK_DATA_AUDIOFORMAT(4) {
++                                      .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 4,
+                                       .altsetting = 2,
+@@ -3052,14 +2307,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
++                      { QUIRK_DATA_IGNORE(5) },
+                       {
+-                              .ifnum = 5,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 6,
+-                              .type = QUIRK_MIDI_MIDIMAN,
+-                              .data = &(const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_MIDIMAN(6) {
+                                       .out_ep =  0x02,
+                                       .out_cables = 0x0001,
+                                       .in_ep = 0x81,
+@@ -3067,33 +2317,21 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .in_cables = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ /* DIGIDESIGN MBOX 3 */
+ {
+       USB_DEVICE(0x0dba, 0x5000),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Digidesign",
+               .product_name = "Mbox 3",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_IGNORE(1) },
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .fmt_bits = 24,
+                                       .channels = 4,
+@@ -3120,9 +2358,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(3) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .fmt_bits = 24,
+                                       .channels = 4,
+@@ -3146,36 +2382,25 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 4,
+-                              .type = QUIRK_MIDI_FIXED_ENDPOINT,
+-                              .data = &(const struct snd_usb_midi_endpoint_info) {
++                              QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ {
+       /* Tascam US122 MKII - playback-only support */
+       USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "TASCAM",
+               .product_name = "US122 MKII",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 2,
+                                       .iface = 1,
+@@ -3196,9 +2421,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3206,20 +2429,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ /* Denon DN-X1600 */
+ {
+       USB_AUDIO_DEVICE(0x154e, 0x500e),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Denon",
+               .product_name = "DN-X1600",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]){
++              QUIRK_DATA_COMPOSITE{
++                      { QUIRK_DATA_IGNORE(0) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE,
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+@@ -3240,9 +2456,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+@@ -3262,13 +2476,8 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_MIDI_STANDARD_INTERFACE,
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_STANDARD_MIDI(4) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3277,17 +2486,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       USB_DEVICE(0x045e, 0x0283),
+       .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Microsoft",
+               .product_name = "XboxLive Headset/Xbox Communicator",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
+                       {
+                               /* playback */
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 1,
+                                       .iface = 0,
+@@ -3303,9 +2508,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                       },
+                       {
+                               /* capture */
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 1,
+                                       .iface = 1,
+@@ -3319,9 +2522,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_max = 16000
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3330,18 +2531,11 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+ {
+       USB_DEVICE(0x200c, 0x100b),
+       .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 1,
+@@ -3360,9 +2554,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3375,28 +2567,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * enabled in create_standard_audio_quirk().
+        */
+       USB_DEVICE(0x1686, 0x00dd),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              /* Playback  */
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+-                      },
+-                      {
+-                              /* Capture */
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+-                      },
+-                      {
+-                              /* Midi */
+-                              .ifnum = 3,
+-                              .type = QUIRK_MIDI_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      },
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(1) }, /* Playback  */
++                      { QUIRK_DATA_STANDARD_AUDIO(2) }, /* Capture */
++                      { QUIRK_DATA_STANDARD_MIDI(3) }, /* Midi */
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3410,18 +2586,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_MIDI_STANDARD_INTERFACE
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_STANDARD_MIDI(QUIRK_ANY_INTERFACE)
+       }
+ },
+ /* Rane SL-1 */
+ {
+       USB_DEVICE(0x13e5, 0x0001),
+-      .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_AUDIO_STANDARD_INTERFACE
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_STANDARD_AUDIO(QUIRK_ANY_INTERFACE)
+         }
+ },
+@@ -3437,24 +2611,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * and only the 48 kHz sample rate works for the playback interface.
+        */
+       USB_DEVICE(0x0a12, 0x1243),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
+-                      /* Capture */
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_IGNORE_INTERFACE,
+-                      },
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
++                      { QUIRK_DATA_IGNORE(1) }, /* Capture */
+                       /* Playback */
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 2,
+@@ -3473,9 +2636,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3488,19 +2649,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * even on windows.
+        */
+       USB_DEVICE(0x19b5, 0x0021),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       /* Playback */
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 1,
+@@ -3519,29 +2673,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+ /* MOTU Microbook II */
+ {
+       USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "MOTU",
+               .product_name = "MicroBookII",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(0) },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 6,
+                                       .iface = 0,
+@@ -3562,9 +2707,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 8,
+                                       .iface = 0,
+@@ -3585,9 +2728,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3599,14 +2740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * The feedback for the output is the input.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0023),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 12,
+                                       .iface = 0,
+@@ -3623,9 +2760,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 10,
+                                       .iface = 0,
+@@ -3643,9 +2778,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3688,14 +2821,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * but not for DVS (Digital Vinyl Systems) like in Mixxx.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // outputs
+                                       .iface = 0,
+@@ -3712,9 +2841,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // inputs
+                                       .iface = 0,
+@@ -3732,9 +2859,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 48000 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3745,14 +2870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * The feedback for the output is the dummy input.
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000e),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 0,
+@@ -3769,9 +2890,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 2,
+                                       .iface = 0,
+@@ -3789,9 +2908,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3802,14 +2919,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * PCM is 6 channels out & 4 channels in @ 44.1 fixed
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000d),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 6, //Master, Headphones & Booth
+                                       .iface = 0,
+@@ -3826,9 +2939,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4, //2x RCA inputs (CH1 & CH2)
+                                       .iface = 0,
+@@ -3846,9 +2957,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3860,14 +2969,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * The Feedback for the output is the input
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001e),
+-              .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 4,
+                                       .iface = 0,
+@@ -3884,9 +2989,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 6,
+                                       .iface = 0,
+@@ -3904,9 +3007,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3917,14 +3018,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * 10 channels playback & 12 channels capture @ 44.1/48/96kHz S24LE
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000a),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 10,
+                                       .iface = 0,
+@@ -3945,9 +3042,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 12,
+                                       .iface = 0,
+@@ -3969,9 +3064,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -3983,14 +3076,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * The Feedback for the output is the input
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0029),
+-              .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 6,
+                                       .iface = 0,
+@@ -4007,9 +3096,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 6,
+                                       .iface = 0,
+@@ -4027,9 +3114,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4047,20 +3132,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+  */
+ {
+       USB_AUDIO_DEVICE(0x534d, 0x0021),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "MacroSilicon",
+               .product_name = "MS210x",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(2) },
+                       {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(3) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 3,
+@@ -4075,9 +3153,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_max = 48000,
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4095,20 +3171,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+  */
+ {
+       USB_AUDIO_DEVICE(0x534d, 0x2109),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "MacroSilicon",
+               .product_name = "MS2109",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_MIXER(2) },
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_MIXER,
+-                      },
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(3) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 3,
+@@ -4123,9 +3192,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_max = 48000,
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4135,14 +3202,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * 8 channels playback & 8 channels capture @ 44.1/48/96kHz S24LE
+        */
+       USB_DEVICE_VENDOR_SPEC(0x08e4, 0x017f),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 0,
+@@ -4161,9 +3224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 0,
+@@ -4183,9 +3244,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4195,14 +3254,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * 10 channels playback & 12 channels capture @ 48kHz S24LE
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001b),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 10,
+                                       .iface = 0,
+@@ -4221,9 +3276,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 12,
+                                       .iface = 0,
+@@ -4241,9 +3294,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 48000 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4255,14 +3306,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * Capture on EP 0x86
+        */
+       USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0163),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 0,
+@@ -4282,9 +3329,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                               }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 0,
+@@ -4304,9 +3349,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 44100, 48000, 96000 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4317,14 +3360,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * and 8 channels in @ 48 fixed (endpoint 0x82).
+        */
+       USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0013),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // outputs
+                                       .iface = 0,
+@@ -4341,9 +3380,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       }
+                       },
+                       {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(0) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8, // inputs
+                                       .iface = 0,
+@@ -4361,9 +3398,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .rate_table = (unsigned int[]) { 48000 }
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4374,28 +3409,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        */
+       USB_DEVICE(0x1395, 0x0300),
+       .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
++      QUIRK_DRIVER_INFO {
++              QUIRK_DATA_COMPOSITE {
+                       // Communication
+-                      {
+-                              .ifnum = 3,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++                      { QUIRK_DATA_STANDARD_AUDIO(3) },
+                       // Recording
+-                      {
+-                              .ifnum = 4,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++                      { QUIRK_DATA_STANDARD_AUDIO(4) },
+                       // Main
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4404,21 +3426,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * Fiero SC-01 (firmware v1.0.0 @ 48 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0023),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
+                       /* Playback */
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+@@ -4438,9 +3453,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                       },
+                       /* Capture */
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+@@ -4459,9 +3472,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .clock = 0x29
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4470,21 +3481,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * Fiero SC-01 (firmware v1.0.0 @ 96 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0024),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
+                       /* Playback */
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+@@ -4504,9 +3508,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                       },
+                       /* Capture */
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+@@ -4525,9 +3527,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .clock = 0x29
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4536,21 +3536,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * Fiero SC-01 (firmware v1.1.0)
+        */
+       USB_DEVICE(0x2b53, 0x0031),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = &(const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE
+-                      },
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_STANDARD_AUDIO(0) },
+                       /* Playback */
+                       {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(1) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+@@ -4571,9 +3564,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                       },
+                       /* Capture */
+                       {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+-                              .data = &(const struct audioformat) {
++                              QUIRK_DATA_AUDIOFORMAT(2) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+@@ -4593,9 +3584,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+                                       .clock = 0x29
+                               }
+                       },
+-                      {
+-                              .ifnum = -1
+-                      }
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+@@ -4604,27 +3593,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
+        * For the standard mode, Mythware XA001AU has ID ffad:a001
+        */
+       USB_DEVICE_VENDOR_SPEC(0xffad, 0xa001),
+-      .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
++      QUIRK_DRIVER_INFO {
+               .vendor_name = "Mythware",
+               .product_name = "XA001AU",
+-              .ifnum = QUIRK_ANY_INTERFACE,
+-              .type = QUIRK_COMPOSITE,
+-              .data = (const struct snd_usb_audio_quirk[]) {
+-                      {
+-                              .ifnum = 0,
+-                              .type = QUIRK_IGNORE_INTERFACE,
+-                      },
+-                      {
+-                              .ifnum = 1,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+-                      },
+-                      {
+-                              .ifnum = 2,
+-                              .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+-                      },
+-                      {
+-                              .ifnum = -1
+-                      }
++              QUIRK_DATA_COMPOSITE {
++                      { QUIRK_DATA_IGNORE(0) },
++                      { QUIRK_DATA_STANDARD_AUDIO(1) },
++                      { QUIRK_DATA_STANDARD_AUDIO(2) },
++                      QUIRK_COMPOSITE_END
+               }
+       }
+ },
+-- 
+2.43.0
+
diff --git a/queue-6.10/alsa-usb-audio-support-multiple-control-interfaces.patch b/queue-6.10/alsa-usb-audio-support-multiple-control-interfaces.patch
new file mode 100644 (file)
index 0000000..03d755c
--- /dev/null
@@ -0,0 +1,659 @@
+From 1900d66454dede84d5e1cdca46b1443b272293a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Aug 2024 17:29:56 -0700
+Subject: ALSA: usb-audio: Support multiple control interfaces
+
+From: Karol Kosik <k.kosik@outlook.com>
+
+[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ]
+
+Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'.
+The problem stems from the driver not being able to find input/output
+terminals required to configure audio streaming. The information about
+those terminals is stored in AudioControl Interface. Numark device
+contains 2 AudioControl Interfaces and the driver checks only one of them.
+
+According to the USB standard, a device can have multiple audio functions,
+each represented by Audio Interface Collection. Every audio function is
+considered to be closed box and will contain unique AudioControl Interface
+and zero or more AudioStreaming and MIDIStreaming Interfaces.
+
+The Numark device adheres to the standard and defines two audio functions:
+- MIDIStreaming function
+- AudioStreaming function
+It starts with MIDI function, followed by the audio function. The driver
+saves the first AudioControl Interface in `snd_usb_audio` structure
+associated with the entire device. It then attempts to use this interface
+to query for terminals and clocks. However, this fails because the correct
+information is stored in the second AudioControl Interface, defined in the
+second Audio Interface Collection.
+
+This patch introduces a structure holding association between each
+MIDI/Audio Interface and its corresponding AudioControl Interface,
+instead of relying on AudioControl Interface defined for the entire
+device. This structure is populated during usb probing phase and leveraged
+later when querying for terminals and when sending USB requests.
+
+Alternative solutions considered include:
+- defining a quirk for Numark where the order of interface is manually
+changed, or terminals are hardcoded in the driver. This solution would
+have fixed only this model, though it seems that device is USB compliant,
+and it also seems that other devices from this company may be affected.
+What's more, it looks like products from other manufacturers have similar
+problems, i.e. Rane One DJ console
+- keeping a list of all AudioControl Interfaces and querying all of them
+to find required information. That would have solved my problem and have
+low probability of breaking other devices, as we would always start with
+the same logic of querying first AudioControl Interface. This solution
+would not have followed the standard though.
+
+This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds
+the first AudioControl Interface, and uses it as a fallback when some
+interfaces are not parsed correctly and lack an associated AudioControl
+Interface, i.e., when configured via quirks.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865
+Signed-off-by: Karol Kosik <k.kosik@outlook.com>
+Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/card.c           |  2 ++
+ sound/usb/clock.c          | 62 ++++++++++++++++++++++++--------------
+ sound/usb/format.c         |  6 ++--
+ sound/usb/helper.c         | 34 +++++++++++++++++++++
+ sound/usb/helper.h         | 10 ++++--
+ sound/usb/mixer.c          |  2 +-
+ sound/usb/mixer_quirks.c   | 17 ++++++-----
+ sound/usb/mixer_scarlett.c |  4 +--
+ sound/usb/power.c          |  3 +-
+ sound/usb/power.h          |  1 +
+ sound/usb/stream.c         | 21 ++++++++-----
+ sound/usb/usbaudio.h       | 12 ++++++++
+ 12 files changed, 127 insertions(+), 47 deletions(-)
+
+diff --git a/sound/usb/card.c b/sound/usb/card.c
+index bdb04fa37a71d..778de9244f1e7 100644
+--- a/sound/usb/card.c
++++ b/sound/usb/card.c
+@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
+               return -EINVAL;
+       }
++      snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
++
+       if (! snd_usb_parse_audio_interface(chip, interface)) {
+               usb_set_interface(dev, interface, 0); /* reset the current interface */
+               return usb_driver_claim_interface(&usb_audio_driver, iface,
+diff --git a/sound/usb/clock.c b/sound/usb/clock.c
+index 60fcb872a80b6..8f85200292f3f 100644
+--- a/sound/usb/clock.c
++++ b/sound/usb/clock.c
+@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto)
+ }
+ #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3)                \
+-static obj *name(struct snd_usb_audio *chip, int id, int proto)       \
++static obj *name(struct snd_usb_audio *chip, int id,  \
++                              const struct audioformat *fmt)  \
+ {                                                                     \
+-      return find_uac_clock_desc(chip->ctrl_intf, id, validator,      \
+-                                 proto == UAC_VERSION_3 ? (type3) : (type2), \
+-                                 proto);                              \
++      struct usb_host_interface *ctrl_intf =  \
++              snd_usb_find_ctrl_interface(chip, fmt->iface); \
++      return find_uac_clock_desc(ctrl_intf, id, validator,    \
++                                 fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \
++                                 fmt->protocol);                              \
+ }
+ DEFINE_FIND_HELPER(snd_usb_find_clock_source,
+@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
+                  union uac23_clock_multiplier_desc, validate_clock_multiplier,
+                  UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER);
+-static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
++static int uac_clock_selector_get_val(struct snd_usb_audio *chip,
++                              int selector_id, int iface_no)
+ {
++      struct usb_host_interface *ctrl_intf;
+       unsigned char buf;
+       int ret;
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
+       ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+                             UAC2_CS_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                             UAC2_CX_CLOCK_SELECTOR << 8,
+-                            snd_usb_ctrl_intf(chip) | (selector_id << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
+                             &buf, sizeof(buf));
+       if (ret < 0)
+@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
+       return buf;
+ }
+-static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
+-                                      unsigned char pin)
++static int uac_clock_selector_set_val(struct snd_usb_audio *chip,
++                                      int selector_id, unsigned char pin, int iface_no)
+ {
++      struct usb_host_interface *ctrl_intf;
+       int ret;
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
+       ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+                             UAC2_CS_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                             UAC2_CX_CLOCK_SELECTOR << 8,
+-                            snd_usb_ctrl_intf(chip) | (selector_id << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
+                             &pin, sizeof(pin));
+       if (ret < 0)
+               return ret;
+@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
+               return -EINVAL;
+       }
+-      ret = uac_clock_selector_get_val(chip, selector_id);
++      ret = uac_clock_selector_get_val(chip, selector_id, iface_no);
+       if (ret < 0)
+               return ret;
+@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
+       unsigned char data;
+       struct usb_device *dev = chip->dev;
+       union uac23_clock_source_desc *cs_desc;
++      struct usb_host_interface *ctrl_intf;
+-      cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
++      cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
+       if (!cs_desc)
+               return false;
+@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
+                       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+                                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                                             UAC2_CS_CONTROL_CLOCK_VALID << 8,
+-                                            snd_usb_ctrl_intf(chip) | (source_id << 8),
++                                            snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
+                                             &data, sizeof(data));
+                       if (err < 0) {
+                               dev_warn(&dev->dev,
+@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
+       struct usb_device *dev = chip->dev;
+       u32 bmControls;
+       union uac23_clock_source_desc *cs_desc;
++      struct usb_host_interface *ctrl_intf;
+-      cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
++      cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
+       if (!cs_desc)
+               return false;
+@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_CS_CONTROL_CLOCK_VALID << 8,
+-                            snd_usb_ctrl_intf(chip) | (source_id << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
+                             &data, sizeof(data));
+       if (err < 0) {
+@@ -274,7 +286,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+       }
+       /* first, see if the ID we're looking at is a clock source already */
+-      source = snd_usb_find_clock_source(chip, entity_id, proto);
++      source = snd_usb_find_clock_source(chip, entity_id, fmt);
+       if (source) {
+               entity_id = GET_VAL(source, proto, bClockID);
+               if (validate && !uac_clock_source_is_valid(chip, fmt,
+@@ -287,7 +299,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+               return entity_id;
+       }
+-      selector = snd_usb_find_clock_selector(chip, entity_id, proto);
++      selector = snd_usb_find_clock_selector(chip, entity_id, fmt);
+       if (selector) {
+               pins = GET_VAL(selector, proto, bNrInPins);
+               clock_id = GET_VAL(selector, proto, bClockID);
+@@ -317,7 +329,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+               /* the entity ID we are looking at is a selector.
+                * find out what it currently selects */
+-              ret = uac_clock_selector_get_val(chip, clock_id);
++              ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface);
+               if (ret < 0) {
+                       if (!chip->autoclock)
+                               return ret;
+@@ -346,7 +358,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+                       if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR ||
+                           !writeable)
+                               return ret;
+-                      err = uac_clock_selector_set_val(chip, entity_id, cur);
++                      err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface);
+                       if (err < 0) {
+                               if (pins == 1) {
+                                       usb_audio_dbg(chip,
+@@ -377,7 +389,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+                       if (ret < 0)
+                               continue;
+-                      err = uac_clock_selector_set_val(chip, entity_id, i);
++                      err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface);
+                       if (err < 0)
+                               continue;
+@@ -391,7 +403,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
+       }
+       /* FIXME: multipliers only act as pass-thru element for now */
+-      multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto);
++      multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt);
+       if (multiplier)
+               return __uac_clock_find_source(chip, fmt,
+                                              GET_VAL(multiplier, proto, bCSourceID),
+@@ -491,11 +503,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
+       struct usb_device *dev = chip->dev;
+       __le32 data;
+       int err;
++      struct usb_host_interface *ctrl_intf;
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, iface);
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8,
+-                            snd_usb_ctrl_intf(chip) | (clock << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+                             &data, sizeof(data));
+       if (err < 0) {
+               dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
+@@ -524,8 +538,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
+       __le32 data;
+       int err;
+       union uac23_clock_source_desc *cs_desc;
++      struct usb_host_interface *ctrl_intf;
+-      cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
++      cs_desc = snd_usb_find_clock_source(chip, clock, fmt);
+       if (!cs_desc)
+               return 0;
+@@ -544,7 +560,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
+       err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8,
+-                            snd_usb_ctrl_intf(chip) | (clock << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+                             &data, sizeof(data));
+       if (err < 0)
+               return err;
+diff --git a/sound/usb/format.c b/sound/usb/format.c
+index 3b45d0ee76938..61c4aca8be09e 100644
+--- a/sound/usb/format.c
++++ b/sound/usb/format.c
+@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
+       unsigned char tmp[2], *data;
+       int nr_triplets, data_size, ret = 0, ret_l6;
+       int clock = snd_usb_clock_find_source(chip, fp, false);
++      struct usb_host_interface *ctrl_intf;
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface);
+       if (clock < 0) {
+               dev_err(&dev->dev,
+                       "%s(): unable to find clock source (clock %d)\n",
+@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
+       ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8,
+-                            snd_usb_ctrl_intf(chip) | (clock << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+                             tmp, sizeof(tmp));
+       if (ret < 0) {
+@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
+       ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8,
+-                            snd_usb_ctrl_intf(chip) | (clock << 8),
++                            snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
+                             data, data_size);
+       if (ret < 0) {
+diff --git a/sound/usb/helper.c b/sound/usb/helper.c
+index bf80e55d013a8..72b671fb2c84c 100644
+--- a/sound/usb/helper.c
++++ b/sound/usb/helper.c
+@@ -130,3 +130,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
+               return NULL;
+       return usb_altnum_to_altsetting(iface, altsetting);
+ }
++
++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
++              int ctrlif)
++{
++      struct usb_device *dev = chip->dev;
++      struct usb_host_interface *host_iface;
++
++      if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
++              dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
++              return -EINVAL;
++      }
++
++      /* find audiocontrol interface */
++      host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
++
++      chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
++      chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
++      chip->num_intf_to_ctrl++;
++
++      return 0;
++}
++
++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
++                                                      int ifnum)
++{
++      int i;
++
++      for (i = 0; i < chip->num_intf_to_ctrl; ++i)
++              if (chip->intf_to_ctrl[i].interface == ifnum)
++                      return chip->intf_to_ctrl[i].ctrl_intf;
++
++      /* Fallback to first audiocontrol interface */
++      return chip->ctrl_intf;
++}
+diff --git a/sound/usb/helper.h b/sound/usb/helper.h
+index e2b51ec96ec62..0372e050b3dc4 100644
+--- a/sound/usb/helper.h
++++ b/sound/usb/helper.h
+@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
+ struct usb_host_interface *
+ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting);
++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
++              int ctrlif);
++
++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
++                                                              int ifnum);
++
+ /*
+  * retrieve usb_interface descriptor from the host interface
+  * (conditional for compatibility with the older API)
+@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
+ #define snd_usb_get_speed(dev) ((dev)->speed)
+-static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
++static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf)
+ {
+-      return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
++      return get_iface_desc(ctrl_intf)->bInterfaceNumber;
+ }
+ /* in validate.c */
+diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
+index 197fd07e69edd..017b50322d88f 100644
+--- a/sound/usb/mixer.c
++++ b/sound/usb/mixer.c
+@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
+                       UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+                       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                       cluster_id,
+-                      snd_usb_ctrl_intf(state->chip),
++                      snd_usb_ctrl_intf(state->mixer->hostif),
+                       &c_header, sizeof(c_header));
+       if (err < 0)
+               goto error;
+diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
+index 212b5e6443d88..1d8bf1ecfed44 100644
+--- a/sound/usb/mixer_quirks.c
++++ b/sound/usb/mixer_quirks.c
+@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                             pval & 0xff00,
+-                            snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
++                            snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
+                             value, 2);
+       if (err < 0)
+               return err;
+@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
+                             UAC_SET_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                             pval & 0xff00,
+-                            snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
++                            snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
+                             value, 2);
+       snd_usb_unlock_shutdown(chip);
+       return err;
+@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
+       return 0;
+ }
+-static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
++static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id)
+ {
++      struct snd_usb_audio *chip = mixer->chip;
+       u16 buf = 0;
+       snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
+                       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+                       (UAC_FU_VOLUME << 8) | ch,
+-                      snd_usb_ctrl_intf(chip) | (id << 8),
++                      snd_usb_ctrl_intf(mixer->hostif) | (id << 8),
+                       &buf, 2);
+ }
+ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
+ {
+       /* fix to 0dB playback volumes */
+-      dell_dock_init_vol(mixer->chip, 1, 16);
+-      dell_dock_init_vol(mixer->chip, 2, 16);
+-      dell_dock_init_vol(mixer->chip, 1, 19);
+-      dell_dock_init_vol(mixer->chip, 2, 19);
++      dell_dock_init_vol(mixer, 1, 16);
++      dell_dock_init_vol(mixer, 2, 16);
++      dell_dock_init_vol(mixer, 1, 19);
++      dell_dock_init_vol(mixer, 2, 19);
+       return 0;
+ }
+diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
+index 0d6e4f15bf77c..ff548041679bb 100644
+--- a/sound/usb/mixer_scarlett.c
++++ b/sound/usb/mixer_scarlett.c
+@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       unsigned char buf[2 * MAX_CHANNELS] = {0, };
+       int wValue = (elem->control << 8) | elem->idx_off;
+-      int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
++      int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
+       int err;
+       err = snd_usb_ctl_msg(chip->dev,
+@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
+       err = snd_usb_ctl_msg(mixer->chip->dev,
+               usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
+               USB_RECIP_INTERFACE | USB_TYPE_CLASS |
+-              USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
++              USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) |
+               (0x29 << 8), sample_rate_buffer, 4);
+       if (err < 0)
+               return err;
+diff --git a/sound/usb/power.c b/sound/usb/power.c
+index 606a2cb23eab6..66bd4daa68fd5 100644
+--- a/sound/usb/power.c
++++ b/sound/usb/power.c
+@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
+                                       le16_to_cpu(pd_desc->waRecoveryTime1);
+                               pd->pd_d2d0_rec =
+                                       le16_to_cpu(pd_desc->waRecoveryTime2);
++                              pd->ctrl_iface = ctrl_iface;
+                               return pd;
+                       }
+               }
+@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip,
+       unsigned char current_state;
+       int err, idx;
+-      idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
++      idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);
+       err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+                             UAC2_CS_CUR,
+diff --git a/sound/usb/power.h b/sound/usb/power.h
+index 396e3e51440a7..1fa92ad0ca925 100644
+--- a/sound/usb/power.h
++++ b/sound/usb/power.h
+@@ -6,6 +6,7 @@ struct snd_usb_power_domain {
+       int pd_id;              /* UAC3 Power Domain ID */
+       int pd_d1d0_rec;        /* D1 to D0 recovery time */
+       int pd_d2d0_rec;        /* D2 to D0 recovery time */
++      struct usb_host_interface *ctrl_iface; /* Control interface */
+ };
+ enum {
+diff --git a/sound/usb/stream.c b/sound/usb/stream.c
+index e14c725acebf2..d70c140813d68 100644
+--- a/sound/usb/stream.c
++++ b/sound/usb/stream.c
+@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+       struct usb_device *dev = chip->dev;
+       struct uac_format_type_i_continuous_descriptor *fmt;
+       unsigned int num_channels = 0, chconfig = 0;
++      struct usb_host_interface *ctrl_intf;
+       struct audioformat *fp;
+       int clock = 0;
+       u64 format;
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
++
+       /* get audio formats */
+       if (protocol == UAC_VERSION_1) {
+               struct uac1_as_header_descriptor *as =
+@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+               format = le16_to_cpu(as->wFormatTag); /* remember the format value */
+-              iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
++              iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf,
+                                                              as->bTerminalLink,
+                                                              protocol);
+               if (iterm) {
+@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+                * lookup the terminal associated to this interface
+                * to extract the clock
+                */
+-              input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
++              input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
+                                                                   as->bTerminalLink,
+                                                                   protocol);
+               if (input_term) {
+@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+                       goto found_clock;
+               }
+-              output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
++              output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
+                                                                     as->bTerminalLink,
+                                                                     protocol);
+               if (output_term) {
+@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+       struct uac3_cluster_header_descriptor *cluster;
+       struct uac3_as_header_descriptor *as = NULL;
+       struct uac3_hc_descriptor_header hc_header;
++      struct usb_host_interface *ctrl_intf;
+       struct snd_pcm_chmap_elem *chmap;
+       struct snd_usb_power_domain *pd;
+       unsigned char badd_profile;
+@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+       int err;
+       badd_profile = chip->badd_profile;
++      ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
+       if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
+               unsigned int maxpacksize =
+@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+                       UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+                       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                       cluster_id,
+-                      snd_usb_ctrl_intf(chip),
++                      snd_usb_ctrl_intf(ctrl_intf),
+                       &hc_header, sizeof(hc_header));
+       if (err < 0)
+               return ERR_PTR(err);
+@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+                       UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+                       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                       cluster_id,
+-                      snd_usb_ctrl_intf(chip),
++                      snd_usb_ctrl_intf(ctrl_intf),
+                       cluster, wLength);
+       if (err < 0) {
+               kfree(cluster);
+@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+        * lookup the terminal associated to this interface
+        * to extract the clock
+        */
+-      input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
++      input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
+                                                           as->bTerminalLink,
+                                                           UAC_VERSION_3);
+       if (input_term) {
+@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+               goto found_clock;
+       }
+-      output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
++      output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
+                                                             as->bTerminalLink,
+                                                             UAC_VERSION_3);
+       if (output_term) {
+@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+                                                              UAC_VERSION_3,
+                                                              iface_no);
+-              pd = snd_usb_find_power_domain(chip->ctrl_intf,
++              pd = snd_usb_find_power_domain(ctrl_intf,
+                                              as->bTerminalLink);
+               /* ok, let's parse further... */
+diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
+index 43d4029edab46..b0f042c996087 100644
+--- a/sound/usb/usbaudio.h
++++ b/sound/usb/usbaudio.h
+@@ -21,6 +21,15 @@ struct media_intf_devnode;
+ #define MAX_CARD_INTERFACES   16
++/*
++ * Structure holding assosiation between Audio Control Interface
++ * and given Streaming or Midi Interface.
++ */
++struct snd_intf_to_ctrl {
++      u8 interface;
++      struct usb_host_interface *ctrl_intf;
++};
++
+ struct snd_usb_audio {
+       int index;
+       struct usb_device *dev;
+@@ -63,6 +72,9 @@ struct snd_usb_audio {
+       struct usb_host_interface *ctrl_intf;   /* the audio control interface */
+       struct media_device *media_dev;
+       struct media_intf_devnode *ctl_intf_media_devnode;
++
++      unsigned int num_intf_to_ctrl;
++      struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
+ };
+ #define USB_AUDIO_IFACE_UNUSED        ((void *)-1L)
+-- 
+2.43.0
+
diff --git a/queue-6.10/arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch b/queue-6.10/arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch
new file mode 100644 (file)
index 0000000..49ef0c8
--- /dev/null
@@ -0,0 +1,62 @@
+From ef4df77fdc02e20156f224327fa9c6bef48c8477 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 16:33:08 +0000
+Subject: arm64: trans_pgd: mark PTEs entries as valid to avoid dead kexec()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Fares Mehanna <faresx@amazon.de>
+
+[ Upstream commit 7eced90b202d63cdc1b9b11b1353adb1389830f9 ]
+
+The reasons for PTEs in the kernel direct map to be marked invalid are not
+limited to kfence / debug pagealloc machinery. In particular,
+memfd_secret() also steals pages with set_direct_map_invalid_noflush().
+
+When building the transitional page tables for kexec from the current
+kernel's page tables, those pages need to become regular writable pages,
+otherwise, if the relocation places kexec segments over such pages, a fault
+will occur during kexec, leading to host going dark during kexec.
+
+This patch addresses the kexec issue by marking any PTE as valid if it is
+not none. While this fixes the kexec crash, it does not address the
+security concern that if processes owning secret memory are not terminated
+before kexec, the secret content will be mapped in the new kernel without
+being scrubbed.
+
+Suggested-by: Jan H. Schönherr <jschoenh@amazon.de>
+Signed-off-by: Fares Mehanna <faresx@amazon.de>
+Link: https://lore.kernel.org/r/20240902163309.97113-1-faresx@amazon.de
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/mm/trans_pgd.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
+index 5139a28130c08..0f7b484cb2ff2 100644
+--- a/arch/arm64/mm/trans_pgd.c
++++ b/arch/arm64/mm/trans_pgd.c
+@@ -42,14 +42,16 @@ static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
+                * the temporary mappings we use during restore.
+                */
+               __set_pte(dst_ptep, pte_mkwrite_novma(pte));
+-      } else if ((debug_pagealloc_enabled() ||
+-                 is_kfence_address((void *)addr)) && !pte_none(pte)) {
++      } else if (!pte_none(pte)) {
+               /*
+                * debug_pagealloc will removed the PTE_VALID bit if
+                * the page isn't in use by the resume kernel. It may have
+                * been in use by the original kernel, in which case we need
+                * to put it back in our copy to do the restore.
+                *
++               * Other cases include kfence / vmalloc / memfd_secret which
++               * may call `set_direct_map_invalid_noflush()`.
++               *
+                * Before marking this entry valid, check the pfn should
+                * be mapped.
+                */
+-- 
+2.43.0
+
diff --git a/queue-6.10/asoc-codecs-wsa883x-handle-reading-version-failure.patch b/queue-6.10/asoc-codecs-wsa883x-handle-reading-version-failure.patch
new file mode 100644 (file)
index 0000000..9a6892b
--- /dev/null
@@ -0,0 +1,72 @@
+From 09cce4885acc9400a4036e876167f112d26277a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 15:52:31 +0200
+Subject: ASoC: codecs: wsa883x: Handle reading version failure
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 2fbf16992e5aa14acf0441320033a01a32309ded ]
+
+If reading version and variant from registers fails (which is unlikely
+but possible, because it is a read over bus), the driver will proceed
+and perform device configuration based on uninitialized stack variables.
+Handle it a bit better - bail out without doing any init and failing the
+update status Soundwire callback.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20240710-asoc-wsa88xx-version-v1-2-f1c54966ccde@linaro.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/wsa883x.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
+index 2169d93989841..1831d4487ba9d 100644
+--- a/sound/soc/codecs/wsa883x.c
++++ b/sound/soc/codecs/wsa883x.c
+@@ -998,15 +998,19 @@ static const struct reg_sequence reg_init[] = {
+       {WSA883X_GMAMP_SUP1, 0xE2},
+ };
+-static void wsa883x_init(struct wsa883x_priv *wsa883x)
++static int wsa883x_init(struct wsa883x_priv *wsa883x)
+ {
+       struct regmap *regmap = wsa883x->regmap;
+-      int variant, version;
++      int variant, version, ret;
+-      regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
++      ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
++      if (ret)
++              return ret;
+       wsa883x->variant = variant & WSA883X_ID_MASK;
+-      regmap_read(regmap, WSA883X_CHIP_ID0, &version);
++      ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version);
++      if (ret)
++              return ret;
+       wsa883x->version = version;
+       switch (wsa883x->variant) {
+@@ -1041,6 +1045,8 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x)
+                                  WSA883X_DRE_OFFSET_MASK,
+                                  wsa883x->comp_offset);
+       }
++
++      return 0;
+ }
+ static int wsa883x_update_status(struct sdw_slave *slave,
+@@ -1049,7 +1055,7 @@ static int wsa883x_update_status(struct sdw_slave *slave,
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
+       if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0)
+-              wsa883x_init(wsa883x);
++              return wsa883x_init(wsa883x);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/asoc-intel-boards-always-check-the-result-of-acpi_de.patch b/queue-6.10/asoc-intel-boards-always-check-the-result-of-acpi_de.patch
new file mode 100644 (file)
index 0000000..1756f03
--- /dev/null
@@ -0,0 +1,174 @@
+From cee6740c36aaef52bf86b3e1691b4ec8aceed96c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 20:32:01 +0800
+Subject: ASoC: Intel: boards: always check the result of
+ acpi_dev_get_first_match_dev()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+
+[ Upstream commit 14e91ddd5c02d8c3e5a682ebfa0546352b459911 ]
+
+The code seems mostly copy-pasted, with some machine drivers
+forgetting to test if the 'adev' result is NULL.
+
+Add this check when missing, and use -ENOENT consistently as an error
+code.
+
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/alsa-devel/918944d2-3d00-465e-a9d1-5d57fc966113@stanley.mountain/T/#u
+Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
+Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
+Link: https://patch.msgid.link/20240827123215.258859-4-yung-chuan.liao@linux.intel.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/bytcht_cx2072x.c | 4 ++++
+ sound/soc/intel/boards/bytcht_da7213.c  | 4 ++++
+ sound/soc/intel/boards/bytcht_es8316.c  | 2 +-
+ sound/soc/intel/boards/bytcr_rt5640.c   | 2 +-
+ sound/soc/intel/boards/bytcr_rt5651.c   | 2 +-
+ sound/soc/intel/boards/cht_bsw_rt5645.c | 4 ++++
+ sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++++
+ sound/soc/intel/boards/sof_es8336.c     | 2 +-
+ sound/soc/intel/boards/sof_wm8804.c     | 4 ++++
+ 9 files changed, 24 insertions(+), 4 deletions(-)
+
+diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c
+index df3c2a7b64d23..8c2b4ab764bba 100644
+--- a/sound/soc/intel/boards/bytcht_cx2072x.c
++++ b/sound/soc/intel/boards/bytcht_cx2072x.c
+@@ -255,7 +255,11 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev)
+               snprintf(codec_name, sizeof(codec_name), "i2c-%s",
+                        acpi_dev_name(adev));
+               byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name;
++      } else {
++              dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++              return -ENOENT;
+       }
++
+       acpi_dev_put(adev);
+       /* override platform name, if required */
+diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c
+index 08c598b7e1eee..9178bbe8d9950 100644
+--- a/sound/soc/intel/boards/bytcht_da7213.c
++++ b/sound/soc/intel/boards/bytcht_da7213.c
+@@ -258,7 +258,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev)
+               snprintf(codec_name, sizeof(codec_name),
+                        "i2c-%s", acpi_dev_name(adev));
+               dailink[dai_index].codecs->name = codec_name;
++      } else {
++              dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++              return -ENOENT;
+       }
++
+       acpi_dev_put(adev);
+       /* override platform name, if required */
+diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
+index 77b91ea4dc32c..3539c9ff0fd2c 100644
+--- a/sound/soc/intel/boards/bytcht_es8316.c
++++ b/sound/soc/intel/boards/bytcht_es8316.c
+@@ -562,7 +562,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
+               byt_cht_es8316_dais[dai_index].codecs->name = codec_name;
+       } else {
+               dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+-              return -ENXIO;
++              return -ENOENT;
+       }
+       codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
+index db4a33680d948..4479825c08b5e 100644
+--- a/sound/soc/intel/boards/bytcr_rt5640.c
++++ b/sound/soc/intel/boards/bytcr_rt5640.c
+@@ -1693,7 +1693,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
+               byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name;
+       } else {
+               dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+-              return -ENXIO;
++              return -ENOENT;
+       }
+       codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
+index 8514b79f389bb..1f54da98aacf4 100644
+--- a/sound/soc/intel/boards/bytcr_rt5651.c
++++ b/sound/soc/intel/boards/bytcr_rt5651.c
+@@ -926,7 +926,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
+               byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name;
+       } else {
+               dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+-              return -ENXIO;
++              return -ENOENT;
+       }
+       codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
+index 1da9ceee4d593..ac23a8b7cafca 100644
+--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
++++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
+@@ -582,7 +582,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
+               snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
+                        "i2c-%s", acpi_dev_name(adev));
+               cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name;
++      } else {
++              dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++              return -ENOENT;
+       }
++
+       /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */
+       codec_dev = acpi_get_first_physical_node(adev);
+       acpi_dev_put(adev);
+diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c
+index d68e5bc755dee..c6c469d51243e 100644
+--- a/sound/soc/intel/boards/cht_bsw_rt5672.c
++++ b/sound/soc/intel/boards/cht_bsw_rt5672.c
+@@ -479,7 +479,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
+               snprintf(drv->codec_name, sizeof(drv->codec_name),
+                        "i2c-%s", acpi_dev_name(adev));
+               cht_dailink[dai_index].codecs->name = drv->codec_name;
++      }  else {
++              dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++              return -ENOENT;
+       }
++
+       acpi_dev_put(adev);
+       /* Use SSP0 on Bay Trail CR devices */
+diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
+index c1fcc156a5752..809532238c44f 100644
+--- a/sound/soc/intel/boards/sof_es8336.c
++++ b/sound/soc/intel/boards/sof_es8336.c
+@@ -681,7 +681,7 @@ static int sof_es8336_probe(struct platform_device *pdev)
+                       dai_links[0].codecs->dai_name = "ES8326 HiFi";
+       } else {
+               dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
+-              return -ENXIO;
++              return -ENOENT;
+       }
+       codec_dev = acpi_get_first_physical_node(adev);
+diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c
+index 4cb0d463bf404..9c5b3f8f09f36 100644
+--- a/sound/soc/intel/boards/sof_wm8804.c
++++ b/sound/soc/intel/boards/sof_wm8804.c
+@@ -270,7 +270,11 @@ static int sof_wm8804_probe(struct platform_device *pdev)
+               snprintf(codec_name, sizeof(codec_name),
+                        "%s%s", "i2c-", acpi_dev_name(adev));
+               dailink[dai_index].codecs->name = codec_name;
++      } else {
++              dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id);
++              return -ENOENT;
+       }
++
+       acpi_dev_put(adev);
+       snd_soc_card_set_drvdata(card, ctx);
+-- 
+2.43.0
+
diff --git a/queue-6.10/ata-pata_serverworks-do-not-use-the-term-blacklist.patch b/queue-6.10/ata-pata_serverworks-do-not-use-the-term-blacklist.patch
new file mode 100644 (file)
index 0000000..572b57e
--- /dev/null
@@ -0,0 +1,65 @@
+From 893be2b55594d369e87cf9e3dea8fc26ec0cc178 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 10:58:36 +0900
+Subject: ata: pata_serverworks: Do not use the term blacklist
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+[ Upstream commit 858048568c9e3887d8b19e101ee72f129d65cb15 ]
+
+Let's not use the term blacklist in the function
+serverworks_osb4_filter() documentation comment and rather simply refer
+to what that function looks at: the list of devices with groken UDMA5.
+
+While at it, also constify the values of the csb_bad_ata100 array.
+
+Of note is that all of this should probably be handled using libata
+quirk mechanism but it is unclear if these UDMA5 quirks are specific
+to this controller only.
+
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/pata_serverworks.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
+index 549ff24a98231..4edddf6bcc150 100644
+--- a/drivers/ata/pata_serverworks.c
++++ b/drivers/ata/pata_serverworks.c
+@@ -46,10 +46,11 @@
+ #define SVWKS_CSB5_REVISION_NEW       0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+ #define SVWKS_CSB6_REVISION   0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
+- * can overrun their FIFOs when used with the CSB5 */
+-
+-static const char *csb_bad_ata100[] = {
++/*
++ * Seagate Barracuda ATA IV Family drives in UDMA mode 5
++ * can overrun their FIFOs when used with the CSB5.
++ */
++static const char * const csb_bad_ata100[] = {
+       "ST320011A",
+       "ST340016A",
+       "ST360021A",
+@@ -163,10 +164,11 @@ static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned in
+  *    @adev: ATA device
+  *    @mask: Mask of proposed modes
+  *
+- *    Check the blacklist and disable UDMA5 if matched
++ *    Check the list of devices with broken UDMA5 and
++ *    disable UDMA5 if matched.
+  */
+-
+-static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask)
++static unsigned int serverworks_csb_filter(struct ata_device *adev,
++                                         unsigned int mask)
+ {
+       const char *p;
+       char model_num[ATA_ID_PROD_LEN + 1];
+-- 
+2.43.0
+
diff --git a/queue-6.10/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch b/queue-6.10/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch
new file mode 100644 (file)
index 0000000..48e55d2
--- /dev/null
@@ -0,0 +1,61 @@
+From 62ee2a44cced011ddb078e8b2c363a85b5be5662 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 11:14:11 +0900
+Subject: ata: sata_sil: Rename sil_blacklist to sil_quirks
+
+From: Damien Le Moal <dlemoal@kernel.org>
+
+[ Upstream commit 93b0f9e11ce511353c65b7f924cf5f95bd9c3aba ]
+
+Rename the array sil_blacklist to sil_quirks as this name is more
+neutral and is also consistent with how this driver define quirks with
+the SIL_QUIRK_XXX flags.
+
+Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
+Reviewed-by: Niklas Cassel <cassel@kernel.org>
+Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ata/sata_sil.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
+index cc77c02482843..df095659bae0f 100644
+--- a/drivers/ata/sata_sil.c
++++ b/drivers/ata/sata_sil.c
+@@ -128,7 +128,7 @@ static const struct pci_device_id sil_pci_tbl[] = {
+ static const struct sil_drivelist {
+       const char *product;
+       unsigned int quirk;
+-} sil_blacklist [] = {
++} sil_quirks[] = {
+       { "ST320012AS",         SIL_QUIRK_MOD15WRITE },
+       { "ST330013AS",         SIL_QUIRK_MOD15WRITE },
+       { "ST340017AS",         SIL_QUIRK_MOD15WRITE },
+@@ -600,8 +600,8 @@ static void sil_thaw(struct ata_port *ap)
+  *    list, and apply the fixups to only the specific
+  *    devices/hosts/firmwares that need it.
+  *
+- *    20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
+- *    The Maxtor quirk is in the blacklist, but I'm keeping the original
++ *    20040111 - Seagate drives affected by the Mod15Write bug are quirked
++ *    The Maxtor quirk is in sil_quirks, but I'm keeping the original
+  *    pessimistic fix for the following reasons...
+  *    - There seems to be less info on it, only one device gleaned off the
+  *    Windows driver, maybe only one is affected.  More info would be greatly
+@@ -620,9 +620,9 @@ static void sil_dev_config(struct ata_device *dev)
+       ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+-      for (n = 0; sil_blacklist[n].product; n++)
+-              if (!strcmp(sil_blacklist[n].product, model_num)) {
+-                      quirks = sil_blacklist[n].quirk;
++      for (n = 0; sil_quirks[n].product; n++)
++              if (!strcmp(sil_quirks[n].product, model_num)) {
++                      quirks = sil_quirks[n].quirk;
+                       break;
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.10/blk_iocost-fix-more-out-of-bound-shifts.patch b/queue-6.10/blk_iocost-fix-more-out-of-bound-shifts.patch
new file mode 100644 (file)
index 0000000..6880282
--- /dev/null
@@ -0,0 +1,80 @@
+From c82b11c13ccf00d24d38b7e229563abeb2db305e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 08:41:36 -0700
+Subject: blk_iocost: fix more out of bound shifts
+
+From: Konstantin Ovsepian <ovs@ovs.to>
+
+[ Upstream commit 9bce8005ec0dcb23a58300e8522fe4a31da606fa ]
+
+Recently running UBSAN caught few out of bound shifts in the
+ioc_forgive_debts() function:
+
+UBSAN: shift-out-of-bounds in block/blk-iocost.c:2142:38
+shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long
+long')
+...
+UBSAN: shift-out-of-bounds in block/blk-iocost.c:2144:30
+shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long
+long')
+...
+Call Trace:
+<IRQ>
+dump_stack_lvl+0xca/0x130
+__ubsan_handle_shift_out_of_bounds+0x22c/0x280
+? __lock_acquire+0x6441/0x7c10
+ioc_timer_fn+0x6cec/0x7750
+? blk_iocost_init+0x720/0x720
+? call_timer_fn+0x5d/0x470
+call_timer_fn+0xfa/0x470
+? blk_iocost_init+0x720/0x720
+__run_timer_base+0x519/0x700
+...
+
+Actual impact of this issue was not identified but I propose to fix the
+undefined behaviour.
+The proposed fix to prevent those out of bound shifts consist of
+precalculating exponent before using it the shift operations by taking
+min value from the actual exponent and maximum possible number of bits.
+
+Reported-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Konstantin Ovsepian <ovs@ovs.to>
+Acked-by: Tejun Heo <tj@kernel.org>
+Link: https://lore.kernel.org/r/20240822154137.2627818-1-ovs@ovs.to
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/blk-iocost.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/block/blk-iocost.c b/block/blk-iocost.c
+index 690ca99dfaca6..5a6098a3db57e 100644
+--- a/block/blk-iocost.c
++++ b/block/blk-iocost.c
+@@ -2076,7 +2076,7 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors,
+                             struct ioc_now *now)
+ {
+       struct ioc_gq *iocg;
+-      u64 dur, usage_pct, nr_cycles;
++      u64 dur, usage_pct, nr_cycles, nr_cycles_shift;
+       /* if no debtor, reset the cycle */
+       if (!nr_debtors) {
+@@ -2138,10 +2138,12 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors,
+               old_debt = iocg->abs_vdebt;
+               old_delay = iocg->delay;
++              nr_cycles_shift = min_t(u64, nr_cycles, BITS_PER_LONG - 1);
+               if (iocg->abs_vdebt)
+-                      iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles ?: 1;
++                      iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles_shift ?: 1;
++
+               if (iocg->delay)
+-                      iocg->delay = iocg->delay >> nr_cycles ?: 1;
++                      iocg->delay = iocg->delay >> nr_cycles_shift ?: 1;
+               iocg_kick_waitq(iocg, true, now);
+-- 
+2.43.0
+
diff --git a/queue-6.10/block-fix-integer-overflow-in-blksecdiscard.patch b/queue-6.10/block-fix-integer-overflow-in-blksecdiscard.patch
new file mode 100644 (file)
index 0000000..e26ad67
--- /dev/null
@@ -0,0 +1,75 @@
+From 5739969a5ed222459f95efdda581664b8b8498c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 22:48:19 +0300
+Subject: block: fix integer overflow in BLKSECDISCARD
+
+From: Alexey Dobriyan <adobriyan@gmail.com>
+
+[ Upstream commit 697ba0b6ec4ae04afb67d3911799b5e2043b4455 ]
+
+I independently rediscovered
+
+       commit 22d24a544b0d49bbcbd61c8c0eaf77d3c9297155
+       block: fix overflow in blk_ioctl_discard()
+
+but for secure erase.
+
+Same problem:
+
+       uint64_t r[2] = {512, 18446744073709551104ULL};
+       ioctl(fd, BLKSECDISCARD, r);
+
+will enter near infinite loop inside blkdev_issue_secure_erase():
+
+       a.out: attempt to access beyond end of device
+       loop0: rw=5, sector=3399043073, nr_sectors = 1024 limit=2048
+       bio_check_eod: 3286214 callbacks suppressed
+
+Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
+Link: https://lore.kernel.org/r/9e64057f-650a-46d1-b9f7-34af391536ef@p183
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/ioctl.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/block/ioctl.c b/block/ioctl.c
+index d570e16958961..4515d4679eefd 100644
+--- a/block/ioctl.c
++++ b/block/ioctl.c
+@@ -126,7 +126,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
+               return -EINVAL;
+       filemap_invalidate_lock(bdev->bd_mapping);
+-      err = truncate_bdev_range(bdev, mode, start, start + len - 1);
++      err = truncate_bdev_range(bdev, mode, start, end - 1);
+       if (err)
+               goto fail;
+@@ -163,7 +163,7 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
+ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
+               void __user *argp)
+ {
+-      uint64_t start, len;
++      uint64_t start, len, end;
+       uint64_t range[2];
+       int err;
+@@ -178,11 +178,12 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
+       len = range[1];
+       if ((start & 511) || (len & 511))
+               return -EINVAL;
+-      if (start + len > bdev_nr_bytes(bdev))
++      if (check_add_overflow(start, len, &end) ||
++          end > bdev_nr_bytes(bdev))
+               return -EINVAL;
+       filemap_invalidate_lock(bdev->bd_mapping);
+-      err = truncate_bdev_range(bdev, mode, start, start + len - 1);
++      err = truncate_bdev_range(bdev, mode, start, end - 1);
+       if (!err)
+               err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
+                                               GFP_KERNEL);
+-- 
+2.43.0
+
diff --git a/queue-6.10/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch b/queue-6.10/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch
new file mode 100644 (file)
index 0000000..b5d859c
--- /dev/null
@@ -0,0 +1,42 @@
+From 2fd8584d645edb1da5ff96ab4845cbbdd4abd5a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 16:40:05 +0800
+Subject: Bluetooth: btrtl: Set msft ext address filter quirk for RTL8852B
+
+From: Hilda Wu <hildawu@realtek.com>
+
+[ Upstream commit 9a0570948c5def5c59e588dc0e009ed850a1f5a1 ]
+
+For tracking multiple devices concurrently with a condition.
+The patch enables the HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER quirk
+on RTL8852B controller.
+
+The quirk setting is based on commit 9e14606d8f38 ("Bluetooth: msft:
+Extended monitor tracking by address filter")
+
+With this setting, when a pattern monitor detects a device, this
+feature issues an address monitor for tracking that device. Let the
+original pattern monitor keep monitor new devices.
+
+Signed-off-by: Hilda Wu <hildawu@realtek.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btrtl.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
+index bfcb41a57655f..78b5d44558d73 100644
+--- a/drivers/bluetooth/btrtl.c
++++ b/drivers/bluetooth/btrtl.c
+@@ -1296,6 +1296,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
+                       btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
+               if (btrtl_dev->project_id == CHIP_ID_8852A ||
++                  btrtl_dev->project_id == CHIP_ID_8852B ||
+                   btrtl_dev->project_id == CHIP_ID_8852C)
+                       set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks);
+-- 
+2.43.0
+
diff --git a/queue-6.10/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch b/queue-6.10/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch
new file mode 100644 (file)
index 0000000..1c2b65e
--- /dev/null
@@ -0,0 +1,67 @@
+From ad42832760001ef079cda6ad2f60244dee4acf02 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Aug 2024 16:58:22 +0800
+Subject: Bluetooth: btusb: Add Realtek RTL8852C support ID 0x0489:0xe122
+
+From: Hilda Wu <hildawu@realtek.com>
+
+[ Upstream commit bdf9557f70e7512bb2f754abf90d9e9958745316 ]
+
+Add the support ID (0x0489, 0xe122) to usb_device_id table for
+Realtek RTL8852C.
+
+The device info from /sys/kernel/debug/usb/devices as below.
+
+T:  Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#=  2 Spd=12   MxCh= 0
+D:  Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
+P:  Vendor=0489 ProdID=e122 Rev= 0.00
+S:  Manufacturer=Realtek
+S:  Product=Bluetooth Radio
+S:  SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
+E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
+E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
+E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
+I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
+E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
+I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
+E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
+I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
+E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
+I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
+E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
+I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
+E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
+
+Signed-off-by: Hilda Wu <hildawu@realtek.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index c41b86608ba86..dd7d9b7fd1c42 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -539,6 +539,8 @@ static const struct usb_device_id quirks_table[] = {
+                                                    BTUSB_WIDEBAND_SPEECH },
+       { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK |
+                                                    BTUSB_WIDEBAND_SPEECH },
++      { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK |
++                                                   BTUSB_WIDEBAND_SPEECH },
+       /* Realtek 8852BE Bluetooth devices */
+       { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
+-- 
+2.43.0
+
diff --git a/queue-6.10/bnxt_en-extend-maximum-length-of-version-string-by-1.patch b/queue-6.10/bnxt_en-extend-maximum-length-of-version-string-by-1.patch
new file mode 100644 (file)
index 0000000..d85fdfa
--- /dev/null
@@ -0,0 +1,42 @@
+From 1b72f78b090785489e61a0e8854f5cfcdcf55b30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Aug 2024 15:32:55 +0100
+Subject: bnxt_en: Extend maximum length of version string by 1 byte
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit ffff7ee843c351ce71d6e0d52f0f20bea35e18c9 ]
+
+This corrects an out-by-one error in the maximum length of the package
+version string. The size argument of snprintf includes space for the
+trailing '\0' byte, so there is no need to allow extra space for it by
+reducing the value of the size argument by 1.
+
+Found by inspection.
+Compile tested only.
+
+Signed-off-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20240813-bnxt-str-v2-1-872050a157e7@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+index 79c09c1cdf936..0032c4ebd7e12 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+@@ -4146,7 +4146,7 @@ static void bnxt_get_pkgver(struct net_device *dev)
+       if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) {
+               len = strlen(bp->fw_ver_str);
+-              snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1,
++              snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len,
+                        "/pkg %s", buf);
+       }
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/bpf-fix-a-sdiv-overflow-issue.patch b/queue-6.10/bpf-fix-a-sdiv-overflow-issue.patch
new file mode 100644 (file)
index 0000000..792a2f2
--- /dev/null
@@ -0,0 +1,202 @@
+From 6ec44d4fe03d8a1df90bf0c47f5655f4883bc6aa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Sep 2024 08:03:26 -0700
+Subject: bpf: Fix a sdiv overflow issue
+
+From: Yonghong Song <yonghong.song@linux.dev>
+
+[ Upstream commit 7dd34d7b7dcf9309fc6224caf4dd5b35bedddcb7 ]
+
+Zac Ecob reported a problem where a bpf program may cause kernel crash due
+to the following error:
+  Oops: divide error: 0000 [#1] PREEMPT SMP KASAN PTI
+
+The failure is due to the below signed divide:
+  LLONG_MIN/-1 where LLONG_MIN equals to -9,223,372,036,854,775,808.
+LLONG_MIN/-1 is supposed to give a positive number 9,223,372,036,854,775,808,
+but it is impossible since for 64-bit system, the maximum positive
+number is 9,223,372,036,854,775,807. On x86_64, LLONG_MIN/-1 will
+cause a kernel exception. On arm64, the result for LLONG_MIN/-1 is
+LLONG_MIN.
+
+Further investigation found all the following sdiv/smod cases may trigger
+an exception when bpf program is running on x86_64 platform:
+  - LLONG_MIN/-1 for 64bit operation
+  - INT_MIN/-1 for 32bit operation
+  - LLONG_MIN%-1 for 64bit operation
+  - INT_MIN%-1 for 32bit operation
+where -1 can be an immediate or in a register.
+
+On arm64, there are no exceptions:
+  - LLONG_MIN/-1 = LLONG_MIN
+  - INT_MIN/-1 = INT_MIN
+  - LLONG_MIN%-1 = 0
+  - INT_MIN%-1 = 0
+where -1 can be an immediate or in a register.
+
+Insn patching is needed to handle the above cases and the patched codes
+produced results aligned with above arm64 result. The below are pseudo
+codes to handle sdiv/smod exceptions including both divisor -1 and divisor 0
+and the divisor is stored in a register.
+
+sdiv:
+      tmp = rX
+      tmp += 1 /* [-1, 0] -> [0, 1]
+      if tmp >(unsigned) 1 goto L2
+      if tmp == 0 goto L1
+      rY = 0
+  L1:
+      rY = -rY;
+      goto L3
+  L2:
+      rY /= rX
+  L3:
+
+smod:
+      tmp = rX
+      tmp += 1 /* [-1, 0] -> [0, 1]
+      if tmp >(unsigned) 1 goto L1
+      if tmp == 1 (is64 ? goto L2 : goto L3)
+      rY = 0;
+      goto L2
+  L1:
+      rY %= rX
+  L2:
+      goto L4  // only when !is64
+  L3:
+      wY = wY  // only when !is64
+  L4:
+
+  [1] https://lore.kernel.org/bpf/tPJLTEh7S_DxFEqAI2Ji5MBSoZVg7_G-Py2iaZpAaWtM961fFTWtsnlzwvTbzBzaUzwQAoNATXKUlt0LZOFgnDcIyKCswAnAGdUF3LBrhGQ=@protonmail.com/
+
+Reported-by: Zac Ecob <zacecob@protonmail.com>
+Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
+Acked-by: Andrii Nakryiko <andrii@kernel.org>
+Link: https://lore.kernel.org/r/20240913150326.1187788-1-yonghong.song@linux.dev
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 93 +++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 89 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 4688dc82f8b06..eb4b4f5b1284f 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -19951,13 +19951,46 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
+                       /* Convert BPF_CLASS(insn->code) == BPF_ALU64 to 32-bit ALU */
+                       insn->code = BPF_ALU | BPF_OP(insn->code) | BPF_SRC(insn->code);
+-              /* Make divide-by-zero exceptions impossible. */
++              /* Make sdiv/smod divide-by-minus-one exceptions impossible. */
++              if ((insn->code == (BPF_ALU64 | BPF_MOD | BPF_K) ||
++                   insn->code == (BPF_ALU64 | BPF_DIV | BPF_K) ||
++                   insn->code == (BPF_ALU | BPF_MOD | BPF_K) ||
++                   insn->code == (BPF_ALU | BPF_DIV | BPF_K)) &&
++                  insn->off == 1 && insn->imm == -1) {
++                      bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
++                      bool isdiv = BPF_OP(insn->code) == BPF_DIV;
++                      struct bpf_insn *patchlet;
++                      struct bpf_insn chk_and_sdiv[] = {
++                              BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++                                           BPF_NEG | BPF_K, insn->dst_reg,
++                                           0, 0, 0),
++                      };
++                      struct bpf_insn chk_and_smod[] = {
++                              BPF_MOV32_IMM(insn->dst_reg, 0),
++                      };
++
++                      patchlet = isdiv ? chk_and_sdiv : chk_and_smod;
++                      cnt = isdiv ? ARRAY_SIZE(chk_and_sdiv) : ARRAY_SIZE(chk_and_smod);
++
++                      new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);
++                      if (!new_prog)
++                              return -ENOMEM;
++
++                      delta    += cnt - 1;
++                      env->prog = prog = new_prog;
++                      insn      = new_prog->insnsi + i + delta;
++                      goto next_insn;
++              }
++
++              /* Make divide-by-zero and divide-by-minus-one exceptions impossible. */
+               if (insn->code == (BPF_ALU64 | BPF_MOD | BPF_X) ||
+                   insn->code == (BPF_ALU64 | BPF_DIV | BPF_X) ||
+                   insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
+                   insn->code == (BPF_ALU | BPF_DIV | BPF_X)) {
+                       bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
+                       bool isdiv = BPF_OP(insn->code) == BPF_DIV;
++                      bool is_sdiv = isdiv && insn->off == 1;
++                      bool is_smod = !isdiv && insn->off == 1;
+                       struct bpf_insn *patchlet;
+                       struct bpf_insn chk_and_div[] = {
+                               /* [R,W]x div 0 -> 0 */
+@@ -19977,10 +20010,62 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
+                               BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+                               BPF_MOV32_REG(insn->dst_reg, insn->dst_reg),
+                       };
++                      struct bpf_insn chk_and_sdiv[] = {
++                              /* [R,W]x sdiv 0 -> 0
++                               * LLONG_MIN sdiv -1 -> LLONG_MIN
++                               * INT_MIN sdiv -1 -> INT_MIN
++                               */
++                              BPF_MOV64_REG(BPF_REG_AX, insn->src_reg),
++                              BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++                                           BPF_ADD | BPF_K, BPF_REG_AX,
++                                           0, 0, 1),
++                              BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++                                           BPF_JGT | BPF_K, BPF_REG_AX,
++                                           0, 4, 1),
++                              BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++                                           BPF_JEQ | BPF_K, BPF_REG_AX,
++                                           0, 1, 0),
++                              BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++                                           BPF_MOV | BPF_K, insn->dst_reg,
++                                           0, 0, 0),
++                              /* BPF_NEG(LLONG_MIN) == -LLONG_MIN == LLONG_MIN */
++                              BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++                                           BPF_NEG | BPF_K, insn->dst_reg,
++                                           0, 0, 0),
++                              BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++                              *insn,
++                      };
++                      struct bpf_insn chk_and_smod[] = {
++                              /* [R,W]x mod 0 -> [R,W]x */
++                              /* [R,W]x mod -1 -> 0 */
++                              BPF_MOV64_REG(BPF_REG_AX, insn->src_reg),
++                              BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
++                                           BPF_ADD | BPF_K, BPF_REG_AX,
++                                           0, 0, 1),
++                              BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++                                           BPF_JGT | BPF_K, BPF_REG_AX,
++                                           0, 3, 1),
++                              BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
++                                           BPF_JEQ | BPF_K, BPF_REG_AX,
++                                           0, 3 + (is64 ? 0 : 1), 1),
++                              BPF_MOV32_IMM(insn->dst_reg, 0),
++                              BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++                              *insn,
++                              BPF_JMP_IMM(BPF_JA, 0, 0, 1),
++                              BPF_MOV32_REG(insn->dst_reg, insn->dst_reg),
++                      };
+-                      patchlet = isdiv ? chk_and_div : chk_and_mod;
+-                      cnt = isdiv ? ARRAY_SIZE(chk_and_div) :
+-                                    ARRAY_SIZE(chk_and_mod) - (is64 ? 2 : 0);
++                      if (is_sdiv) {
++                              patchlet = chk_and_sdiv;
++                              cnt = ARRAY_SIZE(chk_and_sdiv);
++                      } else if (is_smod) {
++                              patchlet = chk_and_smod;
++                              cnt = ARRAY_SIZE(chk_and_smod) - (is64 ? 2 : 0);
++                      } else {
++                              patchlet = isdiv ? chk_and_div : chk_and_mod;
++                              cnt = isdiv ? ARRAY_SIZE(chk_and_div) :
++                                            ARRAY_SIZE(chk_and_mod) - (is64 ? 2 : 0);
++                      }
+                       new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);
+                       if (!new_prog)
+-- 
+2.43.0
+
diff --git a/queue-6.10/bpf-make-the-pointer-returned-by-iter-next-method-va.patch b/queue-6.10/bpf-make-the-pointer-returned-by-iter-next-method-va.patch
new file mode 100644 (file)
index 0000000..ebeb6e8
--- /dev/null
@@ -0,0 +1,108 @@
+From 0b752f35496de47b25c3d5e7487b845d566687c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 21:11:17 +0100
+Subject: bpf: Make the pointer returned by iter next method valid
+
+From: Juntong Deng <juntong.deng@outlook.com>
+
+[ Upstream commit 4cc8c50c9abcb2646a7a4fcef3cea5dcb30c06cf ]
+
+Currently we cannot pass the pointer returned by iter next method as
+argument to KF_TRUSTED_ARGS or KF_RCU kfuncs, because the pointer
+returned by iter next method is not "valid".
+
+This patch sets the pointer returned by iter next method to be valid.
+
+This is based on the fact that if the iterator is implemented correctly,
+then the pointer returned from the iter next method should be valid.
+
+This does not make NULL pointer valid. If the iter next method has
+KF_RET_NULL flag, then the verifier will ask the ebpf program to
+check NULL pointer.
+
+KF_RCU_PROTECTED iterator is a special case, the pointer returned by
+iter next method should only be valid within RCU critical section,
+so it should be with MEM_RCU, not PTR_TRUSTED.
+
+Another special case is bpf_iter_num_next, which returns a pointer with
+base type PTR_TO_MEM. PTR_TO_MEM should not be combined with type flag
+PTR_TRUSTED (PTR_TO_MEM already means the pointer is valid).
+
+The pointer returned by iter next method of other types of iterators
+is with PTR_TRUSTED.
+
+In addition, this patch adds get_iter_from_state to help us get the
+current iterator from the current state.
+
+Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
+Link: https://lore.kernel.org/r/AM6PR03MB584869F8B448EA1C87B7CDA399962@AM6PR03MB5848.eurprd03.prod.outlook.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index c821713249c81..4688dc82f8b06 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -8017,6 +8017,15 @@ static int widen_imprecise_scalars(struct bpf_verifier_env *env,
+       return 0;
+ }
++static struct bpf_reg_state *get_iter_from_state(struct bpf_verifier_state *cur_st,
++                                               struct bpf_kfunc_call_arg_meta *meta)
++{
++      int iter_frameno = meta->iter.frameno;
++      int iter_spi = meta->iter.spi;
++
++      return &cur_st->frame[iter_frameno]->stack[iter_spi].spilled_ptr;
++}
++
+ /* process_iter_next_call() is called when verifier gets to iterator's next
+  * "method" (e.g., bpf_iter_num_next() for numbers iterator) call. We'll refer
+  * to it as just "iter_next()" in comments below.
+@@ -8101,12 +8110,10 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx,
+       struct bpf_verifier_state *cur_st = env->cur_state, *queued_st, *prev_st;
+       struct bpf_func_state *cur_fr = cur_st->frame[cur_st->curframe], *queued_fr;
+       struct bpf_reg_state *cur_iter, *queued_iter;
+-      int iter_frameno = meta->iter.frameno;
+-      int iter_spi = meta->iter.spi;
+       BTF_TYPE_EMIT(struct bpf_iter);
+-      cur_iter = &env->cur_state->frame[iter_frameno]->stack[iter_spi].spilled_ptr;
++      cur_iter = get_iter_from_state(cur_st, meta);
+       if (cur_iter->iter.state != BPF_ITER_STATE_ACTIVE &&
+           cur_iter->iter.state != BPF_ITER_STATE_DRAINED) {
+@@ -8134,7 +8141,7 @@ static int process_iter_next_call(struct bpf_verifier_env *env, int insn_idx,
+               if (!queued_st)
+                       return -ENOMEM;
+-              queued_iter = &queued_st->frame[iter_frameno]->stack[iter_spi].spilled_ptr;
++              queued_iter = get_iter_from_state(queued_st, meta);
+               queued_iter->iter.state = BPF_ITER_STATE_ACTIVE;
+               queued_iter->iter.depth++;
+               if (prev_st)
+@@ -12675,6 +12682,17 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
+                       regs[BPF_REG_0].btf = desc_btf;
+                       regs[BPF_REG_0].type = PTR_TO_BTF_ID;
+                       regs[BPF_REG_0].btf_id = ptr_type_id;
++
++                      if (is_iter_next_kfunc(&meta)) {
++                              struct bpf_reg_state *cur_iter;
++
++                              cur_iter = get_iter_from_state(env->cur_state, &meta);
++
++                              if (cur_iter->type & MEM_RCU) /* KF_RCU_PROTECTED */
++                                      regs[BPF_REG_0].type |= MEM_RCU;
++                              else
++                                      regs[BPF_REG_0].type |= PTR_TRUSTED;
++                      }
+               }
+               if (is_kfunc_ret_null(&meta)) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch b/queue-6.10/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch
new file mode 100644 (file)
index 0000000..64ab089
--- /dev/null
@@ -0,0 +1,55 @@
+From 38c9d180fca76681259493870e8a793193c0f0cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 8 Sep 2024 22:00:09 +0800
+Subject: bpftool: Fix undefined behavior caused by shifting into the sign bit
+
+From: Kuan-Wei Chiu <visitorckw@gmail.com>
+
+[ Upstream commit 4cdc0e4ce5e893bc92255f5f734d983012f2bc2e ]
+
+Replace shifts of '1' with '1U' in bitwise operations within
+__show_dev_tc_bpf() to prevent undefined behavior caused by shifting
+into the sign bit of a signed integer. By using '1U', the operations
+are explicitly performed on unsigned integers, avoiding potential
+integer overflow or sign-related issues.
+
+Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Acked-by: Quentin Monnet <qmo@kernel.org>
+Link: https://lore.kernel.org/bpf/20240908140009.3149781-1-visitorckw@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/bpf/bpftool/net.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
+index 968714b4c3d45..ad2ea6cf2db11 100644
+--- a/tools/bpf/bpftool/net.c
++++ b/tools/bpf/bpftool/net.c
+@@ -482,9 +482,9 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
+               if (prog_flags[i] || json_output) {
+                       NET_START_ARRAY("prog_flags", "%s ");
+                       for (j = 0; prog_flags[i] && j < 32; j++) {
+-                              if (!(prog_flags[i] & (1 << j)))
++                              if (!(prog_flags[i] & (1U << j)))
+                                       continue;
+-                              NET_DUMP_UINT_ONLY(1 << j);
++                              NET_DUMP_UINT_ONLY(1U << j);
+                       }
+                       NET_END_ARRAY("");
+               }
+@@ -493,9 +493,9 @@ static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
+                       if (link_flags[i] || json_output) {
+                               NET_START_ARRAY("link_flags", "%s ");
+                               for (j = 0; link_flags[i] && j < 32; j++) {
+-                                      if (!(link_flags[i] & (1 << j)))
++                                      if (!(link_flags[i] & (1U << j)))
+                                               continue;
+-                                      NET_DUMP_UINT_ONLY(1 << j);
++                                      NET_DUMP_UINT_ONLY(1U << j);
+                               }
+                               NET_END_ARRAY("");
+                       }
+-- 
+2.43.0
+
diff --git a/queue-6.10/bpftool-fix-undefined-behavior-in-qsort-null-0.patch b/queue-6.10/bpftool-fix-undefined-behavior-in-qsort-null-0.patch
new file mode 100644 (file)
index 0000000..606867b
--- /dev/null
@@ -0,0 +1,57 @@
+From 4845ae8332bd9154325ea6e6d3166d113e9a2692 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Sep 2024 23:02:07 +0800
+Subject: bpftool: Fix undefined behavior in qsort(NULL, 0, ...)
+
+From: Kuan-Wei Chiu <visitorckw@gmail.com>
+
+[ Upstream commit f04e2ad394e2755d0bb2d858ecb5598718bf00d5 ]
+
+When netfilter has no entry to display, qsort is called with
+qsort(NULL, 0, ...). This results in undefined behavior, as UBSan
+reports:
+
+net.c:827:2: runtime error: null pointer passed as argument 1, which is declared to never be null
+
+Although the C standard does not explicitly state whether calling qsort
+with a NULL pointer when the size is 0 constitutes undefined behavior,
+Section 7.1.4 of the C standard (Use of library functions) mentions:
+
+"Each of the following statements applies unless explicitly stated
+otherwise in the detailed descriptions that follow: If an argument to a
+function has an invalid value (such as a value outside the domain of
+the function, or a pointer outside the address space of the program, or
+a null pointer, or a pointer to non-modifiable storage when the
+corresponding parameter is not const-qualified) or a type (after
+promotion) not expected by a function with variable number of
+arguments, the behavior is undefined."
+
+To avoid this, add an early return when nf_link_info is NULL to prevent
+calling qsort with a NULL pointer.
+
+Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Reviewed-by: Quentin Monnet <qmo@kernel.org>
+Link: https://lore.kernel.org/bpf/20240910150207.3179306-1-visitorckw@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/bpf/bpftool/net.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
+index ad2ea6cf2db11..0f2106218e1f0 100644
+--- a/tools/bpf/bpftool/net.c
++++ b/tools/bpf/bpftool/net.c
+@@ -824,6 +824,9 @@ static void show_link_netfilter(void)
+               nf_link_count++;
+       }
++      if (!nf_link_info)
++              return;
++
+       qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
+       for (id = 0; id < nf_link_count; id++) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch b/queue-6.10/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch
new file mode 100644 (file)
index 0000000..5120a45
--- /dev/null
@@ -0,0 +1,173 @@
+From bff7fc8c8d969fbd15ecfc8750f2bc232d1dda48 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 18:42:24 +0200
+Subject: can: netlink: avoid call to do_set_data_bittiming callback with stale
+ can_priv::ctrlmode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stefan Mätje <stefan.maetje@esd.eu>
+
+[ Upstream commit 2423cc20087ae9a7b7af575aa62304ef67cad7b6 ]
+
+This patch moves the evaluation of data[IFLA_CAN_CTRLMODE] in function
+can_changelink in front of the evaluation of data[IFLA_CAN_BITTIMING].
+
+This avoids a call to do_set_data_bittiming providing a stale
+can_priv::ctrlmode with a CAN_CTRLMODE_FD flag not matching the
+requested state when switching between a CAN Classic and CAN-FD bitrate.
+
+In the same manner the evaluation of data[IFLA_CAN_CTRLMODE] in function
+can_validate is also moved in front of the evaluation of
+data[IFLA_CAN_BITTIMING].
+
+This is a preparation for patches where the nominal and data bittiming
+may have interdependencies on the driver side depending on the
+CAN_CTRLMODE_FD flag state.
+
+Signed-off-by: Stefan Mätje <stefan.maetje@esd.eu>
+Link: https://patch.msgid.link/20240808164224.213522-1-stefan.maetje@esd.eu
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/can/dev/netlink.c | 102 +++++++++++++++++-----------------
+ 1 file changed, 51 insertions(+), 51 deletions(-)
+
+diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
+index dfdc039d92a6c..01aacdcda2606 100644
+--- a/drivers/net/can/dev/netlink.c
++++ b/drivers/net/can/dev/netlink.c
+@@ -65,15 +65,6 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
+       if (!data)
+               return 0;
+-      if (data[IFLA_CAN_BITTIMING]) {
+-              struct can_bittiming bt;
+-
+-              memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
+-              err = can_validate_bittiming(&bt, extack);
+-              if (err)
+-                      return err;
+-      }
+-
+       if (data[IFLA_CAN_CTRLMODE]) {
+               struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+               u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK;
+@@ -114,6 +105,15 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
+               }
+       }
++      if (data[IFLA_CAN_BITTIMING]) {
++              struct can_bittiming bt;
++
++              memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
++              err = can_validate_bittiming(&bt, extack);
++              if (err)
++                      return err;
++      }
++
+       if (is_can_fd) {
+               if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
+                       return -EOPNOTSUPP;
+@@ -195,48 +195,6 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
+       /* We need synchronization with dev->stop() */
+       ASSERT_RTNL();
+-      if (data[IFLA_CAN_BITTIMING]) {
+-              struct can_bittiming bt;
+-
+-              /* Do not allow changing bittiming while running */
+-              if (dev->flags & IFF_UP)
+-                      return -EBUSY;
+-
+-              /* Calculate bittiming parameters based on
+-               * bittiming_const if set, otherwise pass bitrate
+-               * directly via do_set_bitrate(). Bail out if neither
+-               * is given.
+-               */
+-              if (!priv->bittiming_const && !priv->do_set_bittiming &&
+-                  !priv->bitrate_const)
+-                      return -EOPNOTSUPP;
+-
+-              memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
+-              err = can_get_bittiming(dev, &bt,
+-                                      priv->bittiming_const,
+-                                      priv->bitrate_const,
+-                                      priv->bitrate_const_cnt,
+-                                      extack);
+-              if (err)
+-                      return err;
+-
+-              if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
+-                      NL_SET_ERR_MSG_FMT(extack,
+-                                         "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps",
+-                                         bt.bitrate, priv->bitrate_max);
+-                      return -EINVAL;
+-              }
+-
+-              memcpy(&priv->bittiming, &bt, sizeof(bt));
+-
+-              if (priv->do_set_bittiming) {
+-                      /* Finally, set the bit-timing registers */
+-                      err = priv->do_set_bittiming(dev);
+-                      if (err)
+-                              return err;
+-              }
+-      }
+-
+       if (data[IFLA_CAN_CTRLMODE]) {
+               struct can_ctrlmode *cm;
+               u32 ctrlstatic;
+@@ -284,6 +242,48 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
+                       priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_TDC_MASK;
+       }
++      if (data[IFLA_CAN_BITTIMING]) {
++              struct can_bittiming bt;
++
++              /* Do not allow changing bittiming while running */
++              if (dev->flags & IFF_UP)
++                      return -EBUSY;
++
++              /* Calculate bittiming parameters based on
++               * bittiming_const if set, otherwise pass bitrate
++               * directly via do_set_bitrate(). Bail out if neither
++               * is given.
++               */
++              if (!priv->bittiming_const && !priv->do_set_bittiming &&
++                  !priv->bitrate_const)
++                      return -EOPNOTSUPP;
++
++              memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
++              err = can_get_bittiming(dev, &bt,
++                                      priv->bittiming_const,
++                                      priv->bitrate_const,
++                                      priv->bitrate_const_cnt,
++                                      extack);
++              if (err)
++                      return err;
++
++              if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
++                      NL_SET_ERR_MSG_FMT(extack,
++                                         "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps",
++                                         bt.bitrate, priv->bitrate_max);
++                      return -EINVAL;
++              }
++
++              memcpy(&priv->bittiming, &bt, sizeof(bt));
++
++              if (priv->do_set_bittiming) {
++                      /* Finally, set the bit-timing registers */
++                      err = priv->do_set_bittiming(dev);
++                      if (err)
++                              return err;
++              }
++      }
++
+       if (data[IFLA_CAN_RESTART_MS]) {
+               /* Do not allow changing restart delay while running */
+               if (dev->flags & IFF_UP)
+-- 
+2.43.0
+
diff --git a/queue-6.10/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch b/queue-6.10/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch
new file mode 100644 (file)
index 0000000..90011fb
--- /dev/null
@@ -0,0 +1,71 @@
+From f9571e8ad38d9421f6495a889213df68eaebc9ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Sep 2024 18:32:22 +0200
+Subject: cgroup: Disallow mounting v1 hierarchies without controller
+ implementation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Michal Koutný <mkoutny@suse.com>
+
+[ Upstream commit 3c41382e920f1dd5c9f432948fe799c07af1cced ]
+
+The configs that disable some v1 controllers would still allow mounting
+them but with no controller-specific files. (Making such hierarchies
+equivalent to named v1 hierarchies.) To achieve behavior consistent with
+actual out-compilation of a whole controller, the mounts should treat
+respective controllers as non-existent.
+
+Wrap implementation into a helper function, leverage legacy_files to
+detect compiled out controllers. The effect is that mounts on v1 would
+fail and produce a message like:
+  [ 1543.999081] cgroup: Unknown subsys name 'memory'
+
+Signed-off-by: Michal Koutný <mkoutny@suse.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/cgroup-v1.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
+index b9dbf6bf2779d..784337694a4be 100644
+--- a/kernel/cgroup/cgroup-v1.c
++++ b/kernel/cgroup/cgroup-v1.c
+@@ -46,6 +46,12 @@ bool cgroup1_ssid_disabled(int ssid)
+       return cgroup_no_v1_mask & (1 << ssid);
+ }
++static bool cgroup1_subsys_absent(struct cgroup_subsys *ss)
++{
++      /* Check also dfl_cftypes for file-less controllers, i.e. perf_event */
++      return ss->legacy_cftypes == NULL && ss->dfl_cftypes;
++}
++
+ /**
+  * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
+  * @from: attach to all cgroups of a given task
+@@ -932,7 +938,8 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
+               if (ret != -ENOPARAM)
+                       return ret;
+               for_each_subsys(ss, i) {
+-                      if (strcmp(param->key, ss->legacy_name))
++                      if (strcmp(param->key, ss->legacy_name) ||
++                          cgroup1_subsys_absent(ss))
+                               continue;
+                       if (!cgroup_ssid_enabled(i) || cgroup1_ssid_disabled(i))
+                               return invalfc(fc, "Disabled controller '%s'",
+@@ -1024,7 +1031,8 @@ static int check_cgroupfs_options(struct fs_context *fc)
+       mask = ~((u16)1 << cpuset_cgrp_id);
+ #endif
+       for_each_subsys(ss, i)
+-              if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i))
++              if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i) &&
++                  !cgroup1_subsys_absent(ss))
+                       enabled |= 1 << i;
+       ctx->subsys_mask &= enabled;
+-- 
+2.43.0
+
diff --git a/queue-6.10/coredump-standartize-and-fix-logging.patch b/queue-6.10/coredump-standartize-and-fix-logging.patch
new file mode 100644 (file)
index 0000000..a91cbc5
--- /dev/null
@@ -0,0 +1,178 @@
+From f0a5649db30d6ff2509281ace680db9cc08ce258 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 11:27:24 -0700
+Subject: coredump: Standartize and fix logging
+
+From: Roman Kisel <romank@linux.microsoft.com>
+
+[ Upstream commit c114e9948c2b6a0b400266e59cc656b59e795bca ]
+
+The coredump code does not log the process ID and the comm
+consistently, logs unescaped comm when it does log it, and
+does not always use the ratelimited logging. That makes it
+harder to analyze logs and puts the system at the risk of
+spamming the system log incase something crashes many times
+over and over again.
+
+Fix that by logging TGID and comm (escaped) consistently and
+using the ratelimited logging always.
+
+Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
+Tested-by: Allen Pais <apais@linux.microsoft.com>
+Link: https://lore.kernel.org/r/20240718182743.1959160-2-romank@linux.microsoft.com
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/coredump.c            | 43 +++++++++++++++-------------------------
+ include/linux/coredump.h | 22 ++++++++++++++++++++
+ 2 files changed, 38 insertions(+), 27 deletions(-)
+
+diff --git a/fs/coredump.c b/fs/coredump.c
+index a57a06b80f571..19d3343b93c6b 100644
+--- a/fs/coredump.c
++++ b/fs/coredump.c
+@@ -586,8 +586,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+               struct subprocess_info *sub_info;
+               if (ispipe < 0) {
+-                      printk(KERN_WARNING "format_corename failed\n");
+-                      printk(KERN_WARNING "Aborting core\n");
++                      coredump_report_failure("format_corename failed, aborting core");
+                       goto fail_unlock;
+               }
+@@ -607,27 +606,21 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+                        * right pid if a thread in a multi-threaded
+                        * core_pattern process dies.
+                        */
+-                      printk(KERN_WARNING
+-                              "Process %d(%s) has RLIMIT_CORE set to 1\n",
+-                              task_tgid_vnr(current), current->comm);
+-                      printk(KERN_WARNING "Aborting core\n");
++                      coredump_report_failure("RLIMIT_CORE is set to 1, aborting core");
+                       goto fail_unlock;
+               }
+               cprm.limit = RLIM_INFINITY;
+               dump_count = atomic_inc_return(&core_dump_count);
+               if (core_pipe_limit && (core_pipe_limit < dump_count)) {
+-                      printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",
+-                             task_tgid_vnr(current), current->comm);
+-                      printk(KERN_WARNING "Skipping core dump\n");
++                      coredump_report_failure("over core_pipe_limit, skipping core dump");
+                       goto fail_dropcount;
+               }
+               helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
+                                           GFP_KERNEL);
+               if (!helper_argv) {
+-                      printk(KERN_WARNING "%s failed to allocate memory\n",
+-                             __func__);
++                      coredump_report_failure("%s failed to allocate memory", __func__);
+                       goto fail_dropcount;
+               }
+               for (argi = 0; argi < argc; argi++)
+@@ -644,8 +637,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+               kfree(helper_argv);
+               if (retval) {
+-                      printk(KERN_INFO "Core dump to |%s pipe failed\n",
+-                             cn.corename);
++                      coredump_report_failure("|%s pipe failed", cn.corename);
+                       goto close_fail;
+               }
+       } else {
+@@ -658,10 +650,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+                       goto fail_unlock;
+               if (need_suid_safe && cn.corename[0] != '/') {
+-                      printk(KERN_WARNING "Pid %d(%s) can only dump core "\
+-                              "to fully qualified path!\n",
+-                              task_tgid_vnr(current), current->comm);
+-                      printk(KERN_WARNING "Skipping core dump\n");
++                      coredump_report_failure(
++                              "this process can only dump core to a fully qualified path, skipping core dump");
+                       goto fail_unlock;
+               }
+@@ -730,13 +720,13 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+               idmap = file_mnt_idmap(cprm.file);
+               if (!vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode),
+                                   current_fsuid())) {
+-                      pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
+-                                          cn.corename);
++                      coredump_report_failure("Core dump to %s aborted: "
++                              "cannot preserve file owner", cn.corename);
+                       goto close_fail;
+               }
+               if ((inode->i_mode & 0677) != 0600) {
+-                      pr_info_ratelimited("Core dump to %s aborted: cannot preserve file permissions\n",
+-                                          cn.corename);
++                      coredump_report_failure("Core dump to %s aborted: "
++                              "cannot preserve file permissions", cn.corename);
+                       goto close_fail;
+               }
+               if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
+@@ -757,7 +747,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+                * have this set to NULL.
+                */
+               if (!cprm.file) {
+-                      pr_info("Core dump to |%s disabled\n", cn.corename);
++                      coredump_report_failure("Core dump to |%s disabled", cn.corename);
+                       goto close_fail;
+               }
+               if (!dump_vma_snapshot(&cprm))
+@@ -983,11 +973,10 @@ void validate_coredump_safety(void)
+ {
+       if (suid_dumpable == SUID_DUMP_ROOT &&
+           core_pattern[0] != '/' && core_pattern[0] != '|') {
+-              pr_warn(
+-"Unsafe core_pattern used with fs.suid_dumpable=2.\n"
+-"Pipe handler or fully qualified core dump path required.\n"
+-"Set kernel.core_pattern before fs.suid_dumpable.\n"
+-              );
++
++              coredump_report_failure("Unsafe core_pattern used with fs.suid_dumpable=2: "
++                      "pipe handler or fully qualified core dump path required. "
++                      "Set kernel.core_pattern before fs.suid_dumpable.");
+       }
+ }
+diff --git a/include/linux/coredump.h b/include/linux/coredump.h
+index 0904ba010341a..45e598fe34766 100644
+--- a/include/linux/coredump.h
++++ b/include/linux/coredump.h
+@@ -43,8 +43,30 @@ extern int dump_align(struct coredump_params *cprm, int align);
+ int dump_user_range(struct coredump_params *cprm, unsigned long start,
+                   unsigned long len);
+ extern void do_coredump(const kernel_siginfo_t *siginfo);
++
++/*
++ * Logging for the coredump code, ratelimited.
++ * The TGID and comm fields are added to the message.
++ */
++
++#define __COREDUMP_PRINTK(Level, Format, ...) \
++      do {    \
++              char comm[TASK_COMM_LEN];       \
++      \
++              get_task_comm(comm, current);   \
++              printk_ratelimited(Level "coredump: %d(%*pE): " Format "\n",    \
++                      task_tgid_vnr(current), (int)strlen(comm), comm, ##__VA_ARGS__);        \
++      } while (0)     \
++
++#define coredump_report(fmt, ...) __COREDUMP_PRINTK(KERN_INFO, fmt, ##__VA_ARGS__)
++#define coredump_report_failure(fmt, ...) __COREDUMP_PRINTK(KERN_WARNING, fmt, ##__VA_ARGS__)
++
+ #else
+ static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
++
++#define coredump_report(...)
++#define coredump_report_failure(...)
++
+ #endif
+ #if defined(CONFIG_COREDUMP) && defined(CONFIG_SYSCTL)
+-- 
+2.43.0
+
diff --git a/queue-6.10/crypto-hisilicon-fix-missed-error-branch.patch b/queue-6.10/crypto-hisilicon-fix-missed-error-branch.patch
new file mode 100644 (file)
index 0000000..4a5939a
--- /dev/null
@@ -0,0 +1,69 @@
+From 0141cf80196a1bcd3a305dc815841fa3c23708d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 31 Aug 2024 17:50:07 +0800
+Subject: crypto: hisilicon - fix missed error branch
+
+From: Yang Shen <shenyang39@huawei.com>
+
+[ Upstream commit f386dc64e1a5d3dcb84579119ec350ab026fea88 ]
+
+If an error occurs in the process after the SGL is mapped
+successfully, it need to unmap the SGL.
+
+Otherwise, memory problems may occur.
+
+Signed-off-by: Yang Shen <shenyang39@huawei.com>
+Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/hisilicon/sgl.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c
+index 568acd0aee3fa..c974f95cd126f 100644
+--- a/drivers/crypto/hisilicon/sgl.c
++++ b/drivers/crypto/hisilicon/sgl.c
+@@ -225,7 +225,7 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+       dma_addr_t curr_sgl_dma = 0;
+       struct acc_hw_sge *curr_hw_sge;
+       struct scatterlist *sg;
+-      int sg_n;
++      int sg_n, ret;
+       if (!dev || !sgl || !pool || !hw_sgl_dma || index >= pool->count)
+               return ERR_PTR(-EINVAL);
+@@ -240,14 +240,15 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+       if (sg_n_mapped > pool->sge_nr) {
+               dev_err(dev, "the number of entries in input scatterlist is bigger than SGL pool setting.\n");
+-              return ERR_PTR(-EINVAL);
++              ret = -EINVAL;
++              goto err_unmap;
+       }
+       curr_hw_sgl = acc_get_sgl(pool, index, &curr_sgl_dma);
+       if (IS_ERR(curr_hw_sgl)) {
+               dev_err(dev, "Get SGL error!\n");
+-              dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
+-              return ERR_PTR(-ENOMEM);
++              ret = -ENOMEM;
++              goto err_unmap;
+       }
+       curr_hw_sgl->entry_length_in_sgl = cpu_to_le16(pool->sge_nr);
+       curr_hw_sge = curr_hw_sgl->sge_entries;
+@@ -262,6 +263,11 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev,
+       *hw_sgl_dma = curr_sgl_dma;
+       return curr_hw_sgl;
++
++err_unmap:
++      dma_unmap_sg(dev, sgl, sg_n, DMA_BIDIRECTIONAL);
++
++      return ERR_PTR(ret);
+ }
+ EXPORT_SYMBOL_GPL(hisi_acc_sg_buf_map_to_hw_sgl);
+-- 
+2.43.0
+
diff --git a/queue-6.10/crypto-octeontx-fix-authenc-setkey.patch b/queue-6.10/crypto-octeontx-fix-authenc-setkey.patch
new file mode 100644 (file)
index 0000000..b0e8714
--- /dev/null
@@ -0,0 +1,408 @@
+From f9b0de8781f1488819b6a7ebeff5759c18e4a7f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 12:13:23 +0800
+Subject: crypto: octeontx - Fix authenc setkey
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 311eea7e37c4c0b44b557d0c100860a03b4eab65 ]
+
+Use the generic crypto_authenc_extractkeys helper instead of custom
+parsing code that is slightly broken.  Also fix a number of memory
+leaks by moving memory allocation from setkey to init_tfm (setkey
+can be called multiple times over the life of a tfm).
+
+Finally accept all hash key lengths by running the digest over
+extra-long keys.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../crypto/marvell/octeontx/otx_cptvf_algs.c  | 261 +++++++-----------
+ 1 file changed, 93 insertions(+), 168 deletions(-)
+
+diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
+index 3c5d577d8f0d5..0a1b85ad0057f 100644
+--- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
+@@ -17,7 +17,6 @@
+ #include <crypto/sha2.h>
+ #include <crypto/xts.h>
+ #include <crypto/scatterwalk.h>
+-#include <linux/rtnetlink.h>
+ #include <linux/sort.h>
+ #include <linux/module.h>
+ #include "otx_cptvf.h"
+@@ -66,6 +65,8 @@ static struct cpt_device_table ae_devices = {
+       .count = ATOMIC_INIT(0)
+ };
++static struct otx_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg);
++
+ static inline int get_se_device(struct pci_dev **pdev, int *cpu_num)
+ {
+       int count, ret = 0;
+@@ -509,44 +510,61 @@ static int cpt_aead_init(struct crypto_aead *tfm, u8 cipher_type, u8 mac_type)
+       ctx->cipher_type = cipher_type;
+       ctx->mac_type = mac_type;
++      switch (ctx->mac_type) {
++      case OTX_CPT_SHA1:
++              ctx->hashalg = crypto_alloc_shash("sha1", 0, 0);
++              break;
++
++      case OTX_CPT_SHA256:
++              ctx->hashalg = crypto_alloc_shash("sha256", 0, 0);
++              break;
++
++      case OTX_CPT_SHA384:
++              ctx->hashalg = crypto_alloc_shash("sha384", 0, 0);
++              break;
++
++      case OTX_CPT_SHA512:
++              ctx->hashalg = crypto_alloc_shash("sha512", 0, 0);
++              break;
++      }
++
++      if (IS_ERR(ctx->hashalg))
++              return PTR_ERR(ctx->hashalg);
++
++      crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx));
++
++      if (!ctx->hashalg)
++              return 0;
++
+       /*
+        * When selected cipher is NULL we use HMAC opcode instead of
+        * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms
+        * for calculating ipad and opad
+        */
+       if (ctx->cipher_type != OTX_CPT_CIPHER_NULL) {
+-              switch (ctx->mac_type) {
+-              case OTX_CPT_SHA1:
+-                      ctx->hashalg = crypto_alloc_shash("sha1", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
+-
+-              case OTX_CPT_SHA256:
+-                      ctx->hashalg = crypto_alloc_shash("sha256", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
++              int ss = crypto_shash_statesize(ctx->hashalg);
+-              case OTX_CPT_SHA384:
+-                      ctx->hashalg = crypto_alloc_shash("sha384", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
++              ctx->ipad = kzalloc(ss, GFP_KERNEL);
++              if (!ctx->ipad) {
++                      crypto_free_shash(ctx->hashalg);
++                      return -ENOMEM;
++              }
+-              case OTX_CPT_SHA512:
+-                      ctx->hashalg = crypto_alloc_shash("sha512", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
++              ctx->opad = kzalloc(ss, GFP_KERNEL);
++              if (!ctx->opad) {
++                      kfree(ctx->ipad);
++                      crypto_free_shash(ctx->hashalg);
++                      return -ENOMEM;
+               }
+       }
+-      crypto_aead_set_reqsize_dma(tfm, sizeof(struct otx_cpt_req_ctx));
++      ctx->sdesc = alloc_sdesc(ctx->hashalg);
++      if (!ctx->sdesc) {
++              kfree(ctx->opad);
++              kfree(ctx->ipad);
++              crypto_free_shash(ctx->hashalg);
++              return -ENOMEM;
++      }
+       return 0;
+ }
+@@ -602,8 +620,7 @@ static void otx_cpt_aead_exit(struct crypto_aead *tfm)
+       kfree(ctx->ipad);
+       kfree(ctx->opad);
+-      if (ctx->hashalg)
+-              crypto_free_shash(ctx->hashalg);
++      crypto_free_shash(ctx->hashalg);
+       kfree(ctx->sdesc);
+ }
+@@ -699,7 +716,7 @@ static inline void swap_data64(void *buf, u32 len)
+               *dst = cpu_to_be64p(src);
+ }
+-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
++static int swap_pad(u8 mac_type, u8 *pad)
+ {
+       struct sha512_state *sha512;
+       struct sha256_state *sha256;
+@@ -707,22 +724,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+       switch (mac_type) {
+       case OTX_CPT_SHA1:
+-              sha1 = (struct sha1_state *) in_pad;
++              sha1 = (struct sha1_state *)pad;
+               swap_data32(sha1->state, SHA1_DIGEST_SIZE);
+-              memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE);
+               break;
+       case OTX_CPT_SHA256:
+-              sha256 = (struct sha256_state *) in_pad;
++              sha256 = (struct sha256_state *)pad;
+               swap_data32(sha256->state, SHA256_DIGEST_SIZE);
+-              memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE);
+               break;
+       case OTX_CPT_SHA384:
+       case OTX_CPT_SHA512:
+-              sha512 = (struct sha512_state *) in_pad;
++              sha512 = (struct sha512_state *)pad;
+               swap_data64(sha512->state, SHA512_DIGEST_SIZE);
+-              memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE);
+               break;
+       default:
+@@ -732,55 +746,53 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+       return 0;
+ }
+-static int aead_hmac_init(struct crypto_aead *cipher)
++static int aead_hmac_init(struct crypto_aead *cipher,
++                        struct crypto_authenc_keys *keys)
+ {
+       struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+-      int state_size = crypto_shash_statesize(ctx->hashalg);
+       int ds = crypto_shash_digestsize(ctx->hashalg);
+       int bs = crypto_shash_blocksize(ctx->hashalg);
+-      int authkeylen = ctx->auth_key_len;
++      int authkeylen = keys->authkeylen;
+       u8 *ipad = NULL, *opad = NULL;
+-      int ret = 0, icount = 0;
++      int icount = 0;
++      int ret;
+-      ctx->sdesc = alloc_sdesc(ctx->hashalg);
+-      if (!ctx->sdesc)
+-              return -ENOMEM;
++      if (authkeylen > bs) {
++              ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey,
++                                        authkeylen, ctx->key);
++              if (ret)
++                      return ret;
++              authkeylen = ds;
++      } else
++              memcpy(ctx->key, keys->authkey, authkeylen);
+-      ctx->ipad = kzalloc(bs, GFP_KERNEL);
+-      if (!ctx->ipad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
+-      }
++      ctx->enc_key_len = keys->enckeylen;
++      ctx->auth_key_len = authkeylen;
+-      ctx->opad = kzalloc(bs, GFP_KERNEL);
+-      if (!ctx->opad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
+-      }
++      if (ctx->cipher_type == OTX_CPT_CIPHER_NULL)
++              return keys->enckeylen ? -EINVAL : 0;
+-      ipad = kzalloc(state_size, GFP_KERNEL);
+-      if (!ipad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
++      switch (keys->enckeylen) {
++      case AES_KEYSIZE_128:
++              ctx->key_type = OTX_CPT_AES_128_BIT;
++              break;
++      case AES_KEYSIZE_192:
++              ctx->key_type = OTX_CPT_AES_192_BIT;
++              break;
++      case AES_KEYSIZE_256:
++              ctx->key_type = OTX_CPT_AES_256_BIT;
++              break;
++      default:
++              /* Invalid key length */
++              return -EINVAL;
+       }
+-      opad = kzalloc(state_size, GFP_KERNEL);
+-      if (!opad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
+-      }
++      memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen);
+-      if (authkeylen > bs) {
+-              ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key,
+-                                        authkeylen, ipad);
+-              if (ret)
+-                      goto calc_fail;
+-
+-              authkeylen = ds;
+-      } else {
+-              memcpy(ipad, ctx->key, authkeylen);
+-      }
++      ipad = ctx->ipad;
++      opad = ctx->opad;
++      memcpy(ipad, ctx->key, authkeylen);
+       memset(ipad + authkeylen, 0, bs - authkeylen);
+       memcpy(opad, ipad, bs);
+@@ -798,7 +810,7 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+       crypto_shash_init(&ctx->sdesc->shash);
+       crypto_shash_update(&ctx->sdesc->shash, ipad, bs);
+       crypto_shash_export(&ctx->sdesc->shash, ipad);
+-      ret = copy_pad(ctx->mac_type, ctx->ipad, ipad);
++      ret = swap_pad(ctx->mac_type, ipad);
+       if (ret)
+               goto calc_fail;
+@@ -806,25 +818,9 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+       crypto_shash_init(&ctx->sdesc->shash);
+       crypto_shash_update(&ctx->sdesc->shash, opad, bs);
+       crypto_shash_export(&ctx->sdesc->shash, opad);
+-      ret = copy_pad(ctx->mac_type, ctx->opad, opad);
+-      if (ret)
+-              goto calc_fail;
+-
+-      kfree(ipad);
+-      kfree(opad);
+-
+-      return 0;
++      ret = swap_pad(ctx->mac_type, opad);
+ calc_fail:
+-      kfree(ctx->ipad);
+-      ctx->ipad = NULL;
+-      kfree(ctx->opad);
+-      ctx->opad = NULL;
+-      kfree(ipad);
+-      kfree(opad);
+-      kfree(ctx->sdesc);
+-      ctx->sdesc = NULL;
+-
+       return ret;
+ }
+@@ -832,57 +828,15 @@ static int otx_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher,
+                                          const unsigned char *key,
+                                          unsigned int keylen)
+ {
+-      struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+-      struct crypto_authenc_key_param *param;
+-      int enckeylen = 0, authkeylen = 0;
+-      struct rtattr *rta = (void *)key;
+-      int status = -EINVAL;
+-
+-      if (!RTA_OK(rta, keylen))
+-              goto badkey;
+-
+-      if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+-              goto badkey;
+-
+-      if (RTA_PAYLOAD(rta) < sizeof(*param))
+-              goto badkey;
+-
+-      param = RTA_DATA(rta);
+-      enckeylen = be32_to_cpu(param->enckeylen);
+-      key += RTA_ALIGN(rta->rta_len);
+-      keylen -= RTA_ALIGN(rta->rta_len);
+-      if (keylen < enckeylen)
+-              goto badkey;
++      struct crypto_authenc_keys authenc_keys;
++      int status;
+-      if (keylen > OTX_CPT_MAX_KEY_SIZE)
+-              goto badkey;
+-
+-      authkeylen = keylen - enckeylen;
+-      memcpy(ctx->key, key, keylen);
+-
+-      switch (enckeylen) {
+-      case AES_KEYSIZE_128:
+-              ctx->key_type = OTX_CPT_AES_128_BIT;
+-              break;
+-      case AES_KEYSIZE_192:
+-              ctx->key_type = OTX_CPT_AES_192_BIT;
+-              break;
+-      case AES_KEYSIZE_256:
+-              ctx->key_type = OTX_CPT_AES_256_BIT;
+-              break;
+-      default:
+-              /* Invalid key length */
+-              goto badkey;
+-      }
+-
+-      ctx->enc_key_len = enckeylen;
+-      ctx->auth_key_len = authkeylen;
+-
+-      status = aead_hmac_init(cipher);
++      status = crypto_authenc_extractkeys(&authenc_keys, key, keylen);
+       if (status)
+               goto badkey;
+-      return 0;
++      status = aead_hmac_init(cipher, &authenc_keys);
++
+ badkey:
+       return status;
+ }
+@@ -891,36 +845,7 @@ static int otx_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher,
+                                           const unsigned char *key,
+                                           unsigned int keylen)
+ {
+-      struct otx_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+-      struct crypto_authenc_key_param *param;
+-      struct rtattr *rta = (void *)key;
+-      int enckeylen = 0;
+-
+-      if (!RTA_OK(rta, keylen))
+-              goto badkey;
+-
+-      if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+-              goto badkey;
+-
+-      if (RTA_PAYLOAD(rta) < sizeof(*param))
+-              goto badkey;
+-
+-      param = RTA_DATA(rta);
+-      enckeylen = be32_to_cpu(param->enckeylen);
+-      key += RTA_ALIGN(rta->rta_len);
+-      keylen -= RTA_ALIGN(rta->rta_len);
+-      if (enckeylen != 0)
+-              goto badkey;
+-
+-      if (keylen > OTX_CPT_MAX_KEY_SIZE)
+-              goto badkey;
+-
+-      memcpy(ctx->key, key, keylen);
+-      ctx->enc_key_len = enckeylen;
+-      ctx->auth_key_len = keylen;
+-      return 0;
+-badkey:
+-      return -EINVAL;
++      return otx_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen);
+ }
+ static int otx_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher,
+-- 
+2.43.0
+
diff --git a/queue-6.10/crypto-octeontx2-fix-authenc-setkey.patch b/queue-6.10/crypto-octeontx2-fix-authenc-setkey.patch
new file mode 100644 (file)
index 0000000..fc8b60d
--- /dev/null
@@ -0,0 +1,394 @@
+From 52307b37bb13b345c675f270db9d59b939d939f9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 12:36:19 +0800
+Subject: crypto: octeontx2 - Fix authenc setkey
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 7ccb750dcac8abbfc7743aab0db6a72c1c3703c7 ]
+
+Use the generic crypto_authenc_extractkeys helper instead of custom
+parsing code that is slightly broken.  Also fix a number of memory
+leaks by moving memory allocation from setkey to init_tfm (setkey
+can be called multiple times over the life of a tfm).
+
+Finally accept all hash key lengths by running the digest over
+extra-long keys.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../marvell/octeontx2/otx2_cptvf_algs.c       | 254 +++++++-----------
+ 1 file changed, 90 insertions(+), 164 deletions(-)
+
+diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
+index 1604fc58dc13e..5aa56f20f888c 100644
+--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c
+@@ -11,7 +11,6 @@
+ #include <crypto/xts.h>
+ #include <crypto/gcm.h>
+ #include <crypto/scatterwalk.h>
+-#include <linux/rtnetlink.h>
+ #include <linux/sort.h>
+ #include <linux/module.h>
+ #include "otx2_cptvf.h"
+@@ -55,6 +54,8 @@ static struct cpt_device_table se_devices = {
+       .count = ATOMIC_INIT(0)
+ };
++static struct otx2_cpt_sdesc *alloc_sdesc(struct crypto_shash *alg);
++
+ static inline int get_se_device(struct pci_dev **pdev, int *cpu_num)
+ {
+       int count;
+@@ -598,40 +599,56 @@ static int cpt_aead_init(struct crypto_aead *atfm, u8 cipher_type, u8 mac_type)
+       ctx->cipher_type = cipher_type;
+       ctx->mac_type = mac_type;
++      switch (ctx->mac_type) {
++      case OTX2_CPT_SHA1:
++              ctx->hashalg = crypto_alloc_shash("sha1", 0, 0);
++              break;
++
++      case OTX2_CPT_SHA256:
++              ctx->hashalg = crypto_alloc_shash("sha256", 0, 0);
++              break;
++
++      case OTX2_CPT_SHA384:
++              ctx->hashalg = crypto_alloc_shash("sha384", 0, 0);
++              break;
++
++      case OTX2_CPT_SHA512:
++              ctx->hashalg = crypto_alloc_shash("sha512", 0, 0);
++              break;
++      }
++
++      if (IS_ERR(ctx->hashalg))
++              return PTR_ERR(ctx->hashalg);
++
++      if (ctx->hashalg) {
++              ctx->sdesc = alloc_sdesc(ctx->hashalg);
++              if (!ctx->sdesc) {
++                      crypto_free_shash(ctx->hashalg);
++                      return -ENOMEM;
++              }
++      }
++
+       /*
+        * When selected cipher is NULL we use HMAC opcode instead of
+        * FLEXICRYPTO opcode therefore we don't need to use HASH algorithms
+        * for calculating ipad and opad
+        */
+-      if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL) {
+-              switch (ctx->mac_type) {
+-              case OTX2_CPT_SHA1:
+-                      ctx->hashalg = crypto_alloc_shash("sha1", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
+-
+-              case OTX2_CPT_SHA256:
+-                      ctx->hashalg = crypto_alloc_shash("sha256", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
++      if (ctx->cipher_type != OTX2_CPT_CIPHER_NULL && ctx->hashalg) {
++              int ss = crypto_shash_statesize(ctx->hashalg);
+-              case OTX2_CPT_SHA384:
+-                      ctx->hashalg = crypto_alloc_shash("sha384", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
++              ctx->ipad = kzalloc(ss, GFP_KERNEL);
++              if (!ctx->ipad) {
++                      kfree(ctx->sdesc);
++                      crypto_free_shash(ctx->hashalg);
++                      return -ENOMEM;
++              }
+-              case OTX2_CPT_SHA512:
+-                      ctx->hashalg = crypto_alloc_shash("sha512", 0,
+-                                                        CRYPTO_ALG_ASYNC);
+-                      if (IS_ERR(ctx->hashalg))
+-                              return PTR_ERR(ctx->hashalg);
+-                      break;
++              ctx->opad = kzalloc(ss, GFP_KERNEL);
++              if (!ctx->opad) {
++                      kfree(ctx->ipad);
++                      kfree(ctx->sdesc);
++                      crypto_free_shash(ctx->hashalg);
++                      return -ENOMEM;
+               }
+       }
+       switch (ctx->cipher_type) {
+@@ -713,8 +730,7 @@ static void otx2_cpt_aead_exit(struct crypto_aead *tfm)
+       kfree(ctx->ipad);
+       kfree(ctx->opad);
+-      if (ctx->hashalg)
+-              crypto_free_shash(ctx->hashalg);
++      crypto_free_shash(ctx->hashalg);
+       kfree(ctx->sdesc);
+       if (ctx->fbk_cipher) {
+@@ -788,7 +804,7 @@ static inline void swap_data64(void *buf, u32 len)
+               cpu_to_be64s(src);
+ }
+-static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
++static int swap_pad(u8 mac_type, u8 *pad)
+ {
+       struct sha512_state *sha512;
+       struct sha256_state *sha256;
+@@ -796,22 +812,19 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+       switch (mac_type) {
+       case OTX2_CPT_SHA1:
+-              sha1 = (struct sha1_state *) in_pad;
++              sha1 = (struct sha1_state *)pad;
+               swap_data32(sha1->state, SHA1_DIGEST_SIZE);
+-              memcpy(out_pad, &sha1->state, SHA1_DIGEST_SIZE);
+               break;
+       case OTX2_CPT_SHA256:
+-              sha256 = (struct sha256_state *) in_pad;
++              sha256 = (struct sha256_state *)pad;
+               swap_data32(sha256->state, SHA256_DIGEST_SIZE);
+-              memcpy(out_pad, &sha256->state, SHA256_DIGEST_SIZE);
+               break;
+       case OTX2_CPT_SHA384:
+       case OTX2_CPT_SHA512:
+-              sha512 = (struct sha512_state *) in_pad;
++              sha512 = (struct sha512_state *)pad;
+               swap_data64(sha512->state, SHA512_DIGEST_SIZE);
+-              memcpy(out_pad, &sha512->state, SHA512_DIGEST_SIZE);
+               break;
+       default:
+@@ -821,55 +834,54 @@ static int copy_pad(u8 mac_type, u8 *out_pad, u8 *in_pad)
+       return 0;
+ }
+-static int aead_hmac_init(struct crypto_aead *cipher)
++static int aead_hmac_init(struct crypto_aead *cipher,
++                        struct crypto_authenc_keys *keys)
+ {
+       struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+-      int state_size = crypto_shash_statesize(ctx->hashalg);
+       int ds = crypto_shash_digestsize(ctx->hashalg);
+       int bs = crypto_shash_blocksize(ctx->hashalg);
+-      int authkeylen = ctx->auth_key_len;
++      int authkeylen = keys->authkeylen;
+       u8 *ipad = NULL, *opad = NULL;
+-      int ret = 0, icount = 0;
++      int icount = 0;
++      int ret;
+-      ctx->sdesc = alloc_sdesc(ctx->hashalg);
+-      if (!ctx->sdesc)
+-              return -ENOMEM;
++      if (authkeylen > bs) {
++              ret = crypto_shash_digest(&ctx->sdesc->shash, keys->authkey,
++                                        authkeylen, ctx->key);
++              if (ret)
++                      goto calc_fail;
+-      ctx->ipad = kzalloc(bs, GFP_KERNEL);
+-      if (!ctx->ipad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
+-      }
++              authkeylen = ds;
++      } else
++              memcpy(ctx->key, keys->authkey, authkeylen);
+-      ctx->opad = kzalloc(bs, GFP_KERNEL);
+-      if (!ctx->opad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
+-      }
++      ctx->enc_key_len = keys->enckeylen;
++      ctx->auth_key_len = authkeylen;
+-      ipad = kzalloc(state_size, GFP_KERNEL);
+-      if (!ipad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
+-      }
++      if (ctx->cipher_type == OTX2_CPT_CIPHER_NULL)
++              return keys->enckeylen ? -EINVAL : 0;
+-      opad = kzalloc(state_size, GFP_KERNEL);
+-      if (!opad) {
+-              ret = -ENOMEM;
+-              goto calc_fail;
++      switch (keys->enckeylen) {
++      case AES_KEYSIZE_128:
++              ctx->key_type = OTX2_CPT_AES_128_BIT;
++              break;
++      case AES_KEYSIZE_192:
++              ctx->key_type = OTX2_CPT_AES_192_BIT;
++              break;
++      case AES_KEYSIZE_256:
++              ctx->key_type = OTX2_CPT_AES_256_BIT;
++              break;
++      default:
++              /* Invalid key length */
++              return -EINVAL;
+       }
+-      if (authkeylen > bs) {
+-              ret = crypto_shash_digest(&ctx->sdesc->shash, ctx->key,
+-                                        authkeylen, ipad);
+-              if (ret)
+-                      goto calc_fail;
++      memcpy(ctx->key + authkeylen, keys->enckey, keys->enckeylen);
+-              authkeylen = ds;
+-      } else {
+-              memcpy(ipad, ctx->key, authkeylen);
+-      }
++      ipad = ctx->ipad;
++      opad = ctx->opad;
++      memcpy(ipad, ctx->key, authkeylen);
+       memset(ipad + authkeylen, 0, bs - authkeylen);
+       memcpy(opad, ipad, bs);
+@@ -887,7 +899,7 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+       crypto_shash_init(&ctx->sdesc->shash);
+       crypto_shash_update(&ctx->sdesc->shash, ipad, bs);
+       crypto_shash_export(&ctx->sdesc->shash, ipad);
+-      ret = copy_pad(ctx->mac_type, ctx->ipad, ipad);
++      ret = swap_pad(ctx->mac_type, ipad);
+       if (ret)
+               goto calc_fail;
+@@ -895,25 +907,9 @@ static int aead_hmac_init(struct crypto_aead *cipher)
+       crypto_shash_init(&ctx->sdesc->shash);
+       crypto_shash_update(&ctx->sdesc->shash, opad, bs);
+       crypto_shash_export(&ctx->sdesc->shash, opad);
+-      ret = copy_pad(ctx->mac_type, ctx->opad, opad);
+-      if (ret)
+-              goto calc_fail;
+-
+-      kfree(ipad);
+-      kfree(opad);
+-
+-      return 0;
++      ret = swap_pad(ctx->mac_type, opad);
+ calc_fail:
+-      kfree(ctx->ipad);
+-      ctx->ipad = NULL;
+-      kfree(ctx->opad);
+-      ctx->opad = NULL;
+-      kfree(ipad);
+-      kfree(opad);
+-      kfree(ctx->sdesc);
+-      ctx->sdesc = NULL;
+-
+       return ret;
+ }
+@@ -921,87 +917,17 @@ static int otx2_cpt_aead_cbc_aes_sha_setkey(struct crypto_aead *cipher,
+                                           const unsigned char *key,
+                                           unsigned int keylen)
+ {
+-      struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+-      struct crypto_authenc_key_param *param;
+-      int enckeylen = 0, authkeylen = 0;
+-      struct rtattr *rta = (void *)key;
+-
+-      if (!RTA_OK(rta, keylen))
+-              return -EINVAL;
++      struct crypto_authenc_keys authenc_keys;
+-      if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+-              return -EINVAL;
+-
+-      if (RTA_PAYLOAD(rta) < sizeof(*param))
+-              return -EINVAL;
+-
+-      param = RTA_DATA(rta);
+-      enckeylen = be32_to_cpu(param->enckeylen);
+-      key += RTA_ALIGN(rta->rta_len);
+-      keylen -= RTA_ALIGN(rta->rta_len);
+-      if (keylen < enckeylen)
+-              return -EINVAL;
+-
+-      if (keylen > OTX2_CPT_MAX_KEY_SIZE)
+-              return -EINVAL;
+-
+-      authkeylen = keylen - enckeylen;
+-      memcpy(ctx->key, key, keylen);
+-
+-      switch (enckeylen) {
+-      case AES_KEYSIZE_128:
+-              ctx->key_type = OTX2_CPT_AES_128_BIT;
+-              break;
+-      case AES_KEYSIZE_192:
+-              ctx->key_type = OTX2_CPT_AES_192_BIT;
+-              break;
+-      case AES_KEYSIZE_256:
+-              ctx->key_type = OTX2_CPT_AES_256_BIT;
+-              break;
+-      default:
+-              /* Invalid key length */
+-              return -EINVAL;
+-      }
+-
+-      ctx->enc_key_len = enckeylen;
+-      ctx->auth_key_len = authkeylen;
+-
+-      return aead_hmac_init(cipher);
++      return crypto_authenc_extractkeys(&authenc_keys, key, keylen) ?:
++             aead_hmac_init(cipher, &authenc_keys);
+ }
+ static int otx2_cpt_aead_ecb_null_sha_setkey(struct crypto_aead *cipher,
+                                            const unsigned char *key,
+                                            unsigned int keylen)
+ {
+-      struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(cipher);
+-      struct crypto_authenc_key_param *param;
+-      struct rtattr *rta = (void *)key;
+-      int enckeylen = 0;
+-
+-      if (!RTA_OK(rta, keylen))
+-              return -EINVAL;
+-
+-      if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+-              return -EINVAL;
+-
+-      if (RTA_PAYLOAD(rta) < sizeof(*param))
+-              return -EINVAL;
+-
+-      param = RTA_DATA(rta);
+-      enckeylen = be32_to_cpu(param->enckeylen);
+-      key += RTA_ALIGN(rta->rta_len);
+-      keylen -= RTA_ALIGN(rta->rta_len);
+-      if (enckeylen != 0)
+-              return -EINVAL;
+-
+-      if (keylen > OTX2_CPT_MAX_KEY_SIZE)
+-              return -EINVAL;
+-
+-      memcpy(ctx->key, key, keylen);
+-      ctx->enc_key_len = enckeylen;
+-      ctx->auth_key_len = keylen;
+-
+-      return 0;
++      return otx2_cpt_aead_cbc_aes_sha_setkey(cipher, key, keylen);
+ }
+ static int otx2_cpt_aead_gcm_aes_setkey(struct crypto_aead *cipher,
+-- 
+2.43.0
+
diff --git a/queue-6.10/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch b/queue-6.10/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch
new file mode 100644 (file)
index 0000000..568826f
--- /dev/null
@@ -0,0 +1,249 @@
+From 647614c471b886f98a09d70bcdd4ae44bcf6dcc8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 14:58:35 +0800
+Subject: crypto: simd - Do not call crypto_alloc_tfm during registration
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+[ Upstream commit 3c44d31cb34ce4eb8311a2e73634d57702948230 ]
+
+Algorithm registration is usually carried out during module init,
+where as little work as possible should be carried out.  The SIMD
+code violated this rule by allocating a tfm, this then triggers a
+full test of the algorithm which may dead-lock in certain cases.
+
+SIMD is only allocating the tfm to get at the alg object, which is
+in fact already available as it is what we are registering.  Use
+that directly and remove the crypto_alloc_tfm call.
+
+Also remove some obsolete and unused SIMD API.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/crypto/aes-ce-glue.c     |  2 +-
+ arch/arm/crypto/aes-neonbs-glue.c |  2 +-
+ crypto/simd.c                     | 76 ++++++-------------------------
+ include/crypto/internal/simd.h    | 12 +----
+ 4 files changed, 19 insertions(+), 73 deletions(-)
+
+diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c
+index b668c97663ec0..f5b66f4cf45d9 100644
+--- a/arch/arm/crypto/aes-ce-glue.c
++++ b/arch/arm/crypto/aes-ce-glue.c
+@@ -711,7 +711,7 @@ static int __init aes_init(void)
+               algname = aes_algs[i].base.cra_name + 2;
+               drvname = aes_algs[i].base.cra_driver_name + 2;
+               basename = aes_algs[i].base.cra_driver_name;
+-              simd = simd_skcipher_create_compat(algname, drvname, basename);
++              simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename);
+               err = PTR_ERR(simd);
+               if (IS_ERR(simd))
+                       goto unregister_simds;
+diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c
+index f00f042ef3570..0ca94b90bc4ec 100644
+--- a/arch/arm/crypto/aes-neonbs-glue.c
++++ b/arch/arm/crypto/aes-neonbs-glue.c
+@@ -539,7 +539,7 @@ static int __init aes_init(void)
+               algname = aes_algs[i].base.cra_name + 2;
+               drvname = aes_algs[i].base.cra_driver_name + 2;
+               basename = aes_algs[i].base.cra_driver_name;
+-              simd = simd_skcipher_create_compat(algname, drvname, basename);
++              simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename);
+               err = PTR_ERR(simd);
+               if (IS_ERR(simd))
+                       goto unregister_simds;
+diff --git a/crypto/simd.c b/crypto/simd.c
+index edaa479a1ec5e..d109866641a26 100644
+--- a/crypto/simd.c
++++ b/crypto/simd.c
+@@ -136,27 +136,19 @@ static int simd_skcipher_init(struct crypto_skcipher *tfm)
+       return 0;
+ }
+-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg,
++                                                    const char *algname,
+                                                     const char *drvname,
+                                                     const char *basename)
+ {
+       struct simd_skcipher_alg *salg;
+-      struct crypto_skcipher *tfm;
+-      struct skcipher_alg *ialg;
+       struct skcipher_alg *alg;
+       int err;
+-      tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL,
+-                                  CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
+-      if (IS_ERR(tfm))
+-              return ERR_CAST(tfm);
+-
+-      ialg = crypto_skcipher_alg(tfm);
+-
+       salg = kzalloc(sizeof(*salg), GFP_KERNEL);
+       if (!salg) {
+               salg = ERR_PTR(-ENOMEM);
+-              goto out_put_tfm;
++              goto out;
+       }
+       salg->ialg_name = basename;
+@@ -195,30 +187,16 @@ struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
+       if (err)
+               goto out_free_salg;
+-out_put_tfm:
+-      crypto_free_skcipher(tfm);
++out:
+       return salg;
+ out_free_salg:
+       kfree(salg);
+       salg = ERR_PTR(err);
+-      goto out_put_tfm;
++      goto out;
+ }
+ EXPORT_SYMBOL_GPL(simd_skcipher_create_compat);
+-struct simd_skcipher_alg *simd_skcipher_create(const char *algname,
+-                                             const char *basename)
+-{
+-      char drvname[CRYPTO_MAX_ALG_NAME];
+-
+-      if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >=
+-          CRYPTO_MAX_ALG_NAME)
+-              return ERR_PTR(-ENAMETOOLONG);
+-
+-      return simd_skcipher_create_compat(algname, drvname, basename);
+-}
+-EXPORT_SYMBOL_GPL(simd_skcipher_create);
+-
+ void simd_skcipher_free(struct simd_skcipher_alg *salg)
+ {
+       crypto_unregister_skcipher(&salg->alg);
+@@ -246,7 +224,7 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
+               algname = algs[i].base.cra_name + 2;
+               drvname = algs[i].base.cra_driver_name + 2;
+               basename = algs[i].base.cra_driver_name;
+-              simd = simd_skcipher_create_compat(algname, drvname, basename);
++              simd = simd_skcipher_create_compat(algs + i, algname, drvname, basename);
+               err = PTR_ERR(simd);
+               if (IS_ERR(simd))
+                       goto err_unregister;
+@@ -383,27 +361,19 @@ static int simd_aead_init(struct crypto_aead *tfm)
+       return 0;
+ }
+-struct simd_aead_alg *simd_aead_create_compat(const char *algname,
+-                                            const char *drvname,
+-                                            const char *basename)
++static struct simd_aead_alg *simd_aead_create_compat(struct aead_alg *ialg,
++                                                   const char *algname,
++                                                   const char *drvname,
++                                                   const char *basename)
+ {
+       struct simd_aead_alg *salg;
+-      struct crypto_aead *tfm;
+-      struct aead_alg *ialg;
+       struct aead_alg *alg;
+       int err;
+-      tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL,
+-                              CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC);
+-      if (IS_ERR(tfm))
+-              return ERR_CAST(tfm);
+-
+-      ialg = crypto_aead_alg(tfm);
+-
+       salg = kzalloc(sizeof(*salg), GFP_KERNEL);
+       if (!salg) {
+               salg = ERR_PTR(-ENOMEM);
+-              goto out_put_tfm;
++              goto out;
+       }
+       salg->ialg_name = basename;
+@@ -442,36 +412,20 @@ struct simd_aead_alg *simd_aead_create_compat(const char *algname,
+       if (err)
+               goto out_free_salg;
+-out_put_tfm:
+-      crypto_free_aead(tfm);
++out:
+       return salg;
+ out_free_salg:
+       kfree(salg);
+       salg = ERR_PTR(err);
+-      goto out_put_tfm;
+-}
+-EXPORT_SYMBOL_GPL(simd_aead_create_compat);
+-
+-struct simd_aead_alg *simd_aead_create(const char *algname,
+-                                     const char *basename)
+-{
+-      char drvname[CRYPTO_MAX_ALG_NAME];
+-
+-      if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >=
+-          CRYPTO_MAX_ALG_NAME)
+-              return ERR_PTR(-ENAMETOOLONG);
+-
+-      return simd_aead_create_compat(algname, drvname, basename);
++      goto out;
+ }
+-EXPORT_SYMBOL_GPL(simd_aead_create);
+-void simd_aead_free(struct simd_aead_alg *salg)
++static void simd_aead_free(struct simd_aead_alg *salg)
+ {
+       crypto_unregister_aead(&salg->alg);
+       kfree(salg);
+ }
+-EXPORT_SYMBOL_GPL(simd_aead_free);
+ int simd_register_aeads_compat(struct aead_alg *algs, int count,
+                              struct simd_aead_alg **simd_algs)
+@@ -493,7 +447,7 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count,
+               algname = algs[i].base.cra_name + 2;
+               drvname = algs[i].base.cra_driver_name + 2;
+               basename = algs[i].base.cra_driver_name;
+-              simd = simd_aead_create_compat(algname, drvname, basename);
++              simd = simd_aead_create_compat(algs + i, algname, drvname, basename);
+               err = PTR_ERR(simd);
+               if (IS_ERR(simd))
+                       goto err_unregister;
+diff --git a/include/crypto/internal/simd.h b/include/crypto/internal/simd.h
+index d2316242a9884..be97b97a75dd2 100644
+--- a/include/crypto/internal/simd.h
++++ b/include/crypto/internal/simd.h
+@@ -14,11 +14,10 @@
+ struct simd_skcipher_alg;
+ struct skcipher_alg;
+-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg,
++                                                    const char *algname,
+                                                     const char *drvname,
+                                                     const char *basename);
+-struct simd_skcipher_alg *simd_skcipher_create(const char *algname,
+-                                             const char *basename);
+ void simd_skcipher_free(struct simd_skcipher_alg *alg);
+ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
+@@ -32,13 +31,6 @@ void simd_unregister_skciphers(struct skcipher_alg *algs, int count,
+ struct simd_aead_alg;
+ struct aead_alg;
+-struct simd_aead_alg *simd_aead_create_compat(const char *algname,
+-                                            const char *drvname,
+-                                            const char *basename);
+-struct simd_aead_alg *simd_aead_create(const char *algname,
+-                                     const char *basename);
+-void simd_aead_free(struct simd_aead_alg *alg);
+-
+ int simd_register_aeads_compat(struct aead_alg *algs, int count,
+                              struct simd_aead_alg **simd_algs);
+-- 
+2.43.0
+
diff --git a/queue-6.10/crypto-x86-sha256-add-parentheses-around-macros-sing.patch b/queue-6.10/crypto-x86-sha256-add-parentheses-around-macros-sing.patch
new file mode 100644 (file)
index 0000000..6f308f9
--- /dev/null
@@ -0,0 +1,92 @@
+From d0305bdd838b5c6a7f732265840a33791e7ca8fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Aug 2024 21:48:02 -0700
+Subject: crypto: x86/sha256 - Add parentheses around macros' single arguments
+
+From: Fangrui Song <maskray@google.com>
+
+[ Upstream commit 3363c460ef726ba693704dbcd73b7e7214ccc788 ]
+
+The macros FOUR_ROUNDS_AND_SCHED and DO_4ROUNDS rely on an
+unexpected/undocumented behavior of the GNU assembler, which might
+change in the future
+(https://sourceware.org/bugzilla/show_bug.cgi?id=32073).
+
+    M (1) (2) // 1 arg !? Future: 2 args
+    M 1 + 2   // 1 arg !? Future: 3 args
+
+    M 1 2     // 2 args
+
+Add parentheses around the single arguments to support future GNU
+assembler and LLVM integrated assembler (when the IsOperator hack from
+the following link is dropped).
+
+Link: https://github.com/llvm/llvm-project/commit/055006475e22014b28a070db1bff41ca15f322f0
+Signed-off-by: Fangrui Song <maskray@google.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/crypto/sha256-avx2-asm.S | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S
+index 0ffb072be9561..0bbec1c75cd0b 100644
+--- a/arch/x86/crypto/sha256-avx2-asm.S
++++ b/arch/x86/crypto/sha256-avx2-asm.S
+@@ -592,22 +592,22 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx)
+       leaq    K256+0*32(%rip), INP            ## reuse INP as scratch reg
+       vpaddd  (INP, SRND), X0, XFER
+       vmovdqa XFER, 0*32+_XFER(%rsp, SRND)
+-      FOUR_ROUNDS_AND_SCHED   _XFER + 0*32
++      FOUR_ROUNDS_AND_SCHED   (_XFER + 0*32)
+       leaq    K256+1*32(%rip), INP
+       vpaddd  (INP, SRND), X0, XFER
+       vmovdqa XFER, 1*32+_XFER(%rsp, SRND)
+-      FOUR_ROUNDS_AND_SCHED   _XFER + 1*32
++      FOUR_ROUNDS_AND_SCHED   (_XFER + 1*32)
+       leaq    K256+2*32(%rip), INP
+       vpaddd  (INP, SRND), X0, XFER
+       vmovdqa XFER, 2*32+_XFER(%rsp, SRND)
+-      FOUR_ROUNDS_AND_SCHED   _XFER + 2*32
++      FOUR_ROUNDS_AND_SCHED   (_XFER + 2*32)
+       leaq    K256+3*32(%rip), INP
+       vpaddd  (INP, SRND), X0, XFER
+       vmovdqa XFER, 3*32+_XFER(%rsp, SRND)
+-      FOUR_ROUNDS_AND_SCHED   _XFER + 3*32
++      FOUR_ROUNDS_AND_SCHED   (_XFER + 3*32)
+       add     $4*32, SRND
+       cmp     $3*4*32, SRND
+@@ -618,12 +618,12 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx)
+       leaq    K256+0*32(%rip), INP
+       vpaddd  (INP, SRND), X0, XFER
+       vmovdqa XFER, 0*32+_XFER(%rsp, SRND)
+-      DO_4ROUNDS      _XFER + 0*32
++      DO_4ROUNDS      (_XFER + 0*32)
+       leaq    K256+1*32(%rip), INP
+       vpaddd  (INP, SRND), X1, XFER
+       vmovdqa XFER, 1*32+_XFER(%rsp, SRND)
+-      DO_4ROUNDS      _XFER + 1*32
++      DO_4ROUNDS      (_XFER + 1*32)
+       add     $2*32, SRND
+       vmovdqa X2, X0
+@@ -651,8 +651,8 @@ SYM_TYPED_FUNC_START(sha256_transform_rorx)
+       xor     SRND, SRND
+ .align 16
+ .Lloop3:
+-      DO_4ROUNDS       _XFER + 0*32 + 16
+-      DO_4ROUNDS       _XFER + 1*32 + 16
++      DO_4ROUNDS      (_XFER + 0*32 + 16)
++      DO_4ROUNDS      (_XFER + 1*32 + 16)
+       add     $2*32, SRND
+       cmp     $4*4*32, SRND
+       jb      .Lloop3
+-- 
+2.43.0
+
diff --git a/queue-6.10/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch b/queue-6.10/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch
new file mode 100644 (file)
index 0000000..394b357
--- /dev/null
@@ -0,0 +1,115 @@
+From d1d69a973092a4e75c8b3caaf25d9ebb8e6babc6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 15:51:12 +0100
+Subject: drivers/perf: arm_spe: Use perf_allow_kernel() for permissions
+
+From: James Clark <james.clark@linaro.org>
+
+[ Upstream commit 5e9629d0ae977d6f6916d7e519724804e95f0b07 ]
+
+Use perf_allow_kernel() for 'pa_enable' (physical addresses),
+'pct_enable' (physical timestamps) and context IDs. This means that
+perf_event_paranoid is now taken into account and LSM hooks can be used,
+which is more consistent with other perf_event_open calls. For example
+PERF_SAMPLE_PHYS_ADDR uses perf_allow_kernel() rather than just
+perfmon_capable().
+
+This also indirectly fixes the following error message which is
+misleading because perf_event_paranoid is not taken into account by
+perfmon_capable():
+
+  $ perf record -e arm_spe/pa_enable/
+
+  Error:
+  Access to performance monitoring and observability operations is
+  limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid
+  setting ...
+
+Suggested-by: Al Grant <al.grant@arm.com>
+Signed-off-by: James Clark <james.clark@linaro.org>
+Link: https://lore.kernel.org/r/20240827145113.1224604-1-james.clark@linaro.org
+Link: https://lore.kernel.org/all/20240807120039.GD37996@noisy.programming.kicks-ass.net/
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/perf/arm_spe_pmu.c | 9 ++++-----
+ include/linux/perf_event.h | 8 +-------
+ kernel/events/core.c       | 9 +++++++++
+ 3 files changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
+index 9100d82bfabc0..3569050f9cf37 100644
+--- a/drivers/perf/arm_spe_pmu.c
++++ b/drivers/perf/arm_spe_pmu.c
+@@ -41,7 +41,7 @@
+ /*
+  * Cache if the event is allowed to trace Context information.
+- * This allows us to perform the check, i.e, perfmon_capable(),
++ * This allows us to perform the check, i.e, perf_allow_kernel(),
+  * in the context of the event owner, once, during the event_init().
+  */
+ #define SPE_PMU_HW_FLAGS_CX                   0x00001
+@@ -50,7 +50,7 @@ static_assert((PERF_EVENT_FLAG_ARCH & SPE_PMU_HW_FLAGS_CX) == SPE_PMU_HW_FLAGS_C
+ static void set_spe_event_has_cx(struct perf_event *event)
+ {
+-      if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
++      if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && !perf_allow_kernel(&event->attr))
+               event->hw.flags |= SPE_PMU_HW_FLAGS_CX;
+ }
+@@ -745,9 +745,8 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
+       set_spe_event_has_cx(event);
+       reg = arm_spe_event_to_pmscr(event);
+-      if (!perfmon_capable() &&
+-          (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT)))
+-              return -EACCES;
++      if (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT))
++              return perf_allow_kernel(&event->attr);
+       return 0;
+ }
+diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
+index 393fb13733b02..a7f1a3a4d1dce 100644
+--- a/include/linux/perf_event.h
++++ b/include/linux/perf_event.h
+@@ -1608,13 +1608,7 @@ static inline int perf_is_paranoid(void)
+       return sysctl_perf_event_paranoid > -1;
+ }
+-static inline int perf_allow_kernel(struct perf_event_attr *attr)
+-{
+-      if (sysctl_perf_event_paranoid > 1 && !perfmon_capable())
+-              return -EACCES;
+-
+-      return security_perf_event_open(attr, PERF_SECURITY_KERNEL);
+-}
++int perf_allow_kernel(struct perf_event_attr *attr);
+ static inline int perf_allow_cpu(struct perf_event_attr *attr)
+ {
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 36191add55c37..081d9692ce747 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -13362,6 +13362,15 @@ const struct perf_event_attr *perf_event_attrs(struct perf_event *event)
+       return &event->attr;
+ }
++int perf_allow_kernel(struct perf_event_attr *attr)
++{
++      if (sysctl_perf_event_paranoid > 1 && !perfmon_capable())
++              return -EACCES;
++
++      return security_perf_event_open(attr, PERF_SECURITY_KERNEL);
++}
++EXPORT_SYMBOL_GPL(perf_allow_kernel);
++
+ /*
+  * Inherit an event from parent task to child task.
+  *
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch b/queue-6.10/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch
new file mode 100644 (file)
index 0000000..db31e27
--- /dev/null
@@ -0,0 +1,54 @@
+From 3b3000be1d25b696bdd18e588ec59a5967cf78fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 12:35:13 +0530
+Subject: drm/amd/display: Add null check for 'afb' in
+ amdgpu_dm_plane_handle_cursor_update (v2)
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit cd9e9e0852d501f169aa3bb34e4b413d2eb48c37 ]
+
+This commit adds a null check for the 'afb' variable in the
+amdgpu_dm_plane_handle_cursor_update function. Previously, 'afb' was
+assumed to be null, but was used later in the code without a null check.
+This could potentially lead to a null pointer dereference.
+
+Changes since v1:
+- Moved the null check for 'afb' to the line where 'afb' is used. (Alex)
+
+Fixes the below:
+drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_plane.c:1298 amdgpu_dm_plane_handle_cursor_update() error: we previously assumed 'afb' could be null (see line 1252)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Co-developed-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+index 7d47acdd11d55..fe7a99aee47dd 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+@@ -1285,7 +1285,8 @@ void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane,
+           adev->dm.dc->caps.color.dpp.gamma_corr)
+               attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1;
+-      attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
++      if (afb)
++              attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
+       if (crtc_state->stream) {
+               mutex_lock(&adev->dm.dc_lock);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch b/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch
new file mode 100644 (file)
index 0000000..83abc8f
--- /dev/null
@@ -0,0 +1,67 @@
+From d832dd4067b47f8b1a95dd4eb5c0e964d13f3e57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 16:21:19 +0530
+Subject: drm/amd/display: Add NULL check for clk_mgr and clk_mgr->funcs in
+ dcn30_init_hw
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit cba7fec864172dadd953daefdd26e01742b71a6a ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn30_init_hw` function. The issue could occur when `dc->clk_mgr` or
+`dc->clk_mgr->funcs` is null.
+
+The fix adds a check to ensure `dc->clk_mgr` and `dc->clk_mgr->funcs` is
+not null before accessing its functions. This prevents a potential null
+pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/hwss/dcn30/dcn30_hwseq.c:789 dcn30_init_hw() error: we previously assumed 'dc->clk_mgr' could be null (see line 628)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Alex Hung <alex.hung@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/hwss/dcn30/dcn30_hwseq.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+index 05c5d4f04e1bd..0f72a54e92af6 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+@@ -626,7 +626,7 @@ void dcn30_init_hw(struct dc *dc)
+       uint32_t backlight = MAX_BACKLIGHT_LEVEL;
+       uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+-      if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
++      if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks)
+               dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
+       // Initialize the dccg
+@@ -787,11 +787,12 @@ void dcn30_init_hw(struct dc *dc)
+       if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
+               dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
+-      if (dc->clk_mgr->funcs->notify_wm_ranges)
++      if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
+               dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
+       //if softmax is enabled then hardmax will be set by a different call
+-      if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)
++      if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk &&
++          !dc->clk_mgr->dc_mode_softmax_enabled)
+               dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
+       if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch b/queue-6.10/drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch
new file mode 100644 (file)
index 0000000..edff9a0
--- /dev/null
@@ -0,0 +1,65 @@
+From 62a74751c15fea9c06713204890b9e8fde70f1d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 16:44:40 +0530
+Subject: drm/amd/display: Add NULL check for clk_mgr in dcn32_init_hw
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit c395fd47d1565bd67671f45cca281b3acc2c31ef ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn32_init_hw` function. The issue could occur when `dc->clk_mgr` is
+null.
+
+The fix adds a check to ensure `dc->clk_mgr` is not null before
+accessing its functions. This prevents a potential null pointer
+dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/hwss/dcn32/dcn32_hwseq.c:961 dcn32_init_hw() error: we previously assumed 'dc->clk_mgr' could be null (see line 782)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Alex Hung <alex.hung@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/hwss/dcn32/dcn32_hwseq.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+index 5fc377f51f562..aaf576f30a777 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+@@ -752,7 +752,7 @@ void dcn32_init_hw(struct dc *dc)
+       uint32_t backlight = MAX_BACKLIGHT_LEVEL;
+       uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+-      if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
++      if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks)
+               dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
+       // Initialize the dccg
+@@ -931,10 +931,11 @@ void dcn32_init_hw(struct dc *dc)
+       if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
+               dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
+-      if (dc->clk_mgr->funcs->notify_wm_ranges)
++      if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
+               dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
+-      if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)
++      if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->set_hard_max_memclk &&
++          !dc->clk_mgr->dc_mode_softmax_enabled)
+               dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
+       if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch b/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch
new file mode 100644 (file)
index 0000000..7a0e771
--- /dev/null
@@ -0,0 +1,53 @@
+From cb38ad368fde8941cd8c9be6f1062bf6c97ba182 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 13:09:28 +0530
+Subject: drm/amd/display: Add NULL check for function pointer in
+ dcn20_set_output_transfer_func
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 62ed6f0f198da04e884062264df308277628004f ]
+
+This commit adds a null check for the set_output_gamma function pointer
+in the dcn20_set_output_transfer_func function. Previously,
+set_output_gamma was being checked for null at line 1030, but then it
+was being dereferenced without any null check at line 1048. This could
+potentially lead to a null pointer dereference error if set_output_gamma
+is null.
+
+To fix this, we now ensure that set_output_gamma is not null before
+dereferencing it. We do this by adding a null check for set_output_gamma
+before the call to set_output_gamma at line 1048.
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/hwss/dcn20/dcn20_hwseq.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+index 7d833fa6dd77c..58e8b7482f4f5 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+@@ -1040,7 +1040,8 @@ bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
+       /*
+        * if above if is not executed then 'params' equal to 0 and set in bypass
+        */
+-      mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
++      if (mpc->funcs->set_output_gamma)
++              mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
+       return true;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch-29584 b/queue-6.10/drm-amd-display-add-null-check-for-function-pointer-.patch-29584
new file mode 100644 (file)
index 0000000..5151454
--- /dev/null
@@ -0,0 +1,53 @@
+From fca9b6da616d9b8b455d5aa1cd82d144df43e3bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 13:15:00 +0530
+Subject: drm/amd/display: Add NULL check for function pointer in
+ dcn32_set_output_transfer_func
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 28574b08c70e56d34d6f6379326a860b96749051 ]
+
+This commit adds a null check for the set_output_gamma function pointer
+in the dcn32_set_output_transfer_func function. Previously,
+set_output_gamma was being checked for null, but then it was being
+dereferenced without any null check. This could lead to a null pointer
+dereference if set_output_gamma is null.
+
+To fix this, we now ensure that set_output_gamma is not null before
+dereferencing it. We do this by adding a null check for set_output_gamma
+before the call to set_output_gamma.
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/hwss/dcn32/dcn32_hwseq.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+index aaf576f30a777..c050acc4ff065 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+@@ -581,7 +581,9 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
+               }
+       }
+-      mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
++      if (mpc->funcs->set_output_gamma)
++              mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
++
+       return ret;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch b/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch
new file mode 100644 (file)
index 0000000..ec8f302
--- /dev/null
@@ -0,0 +1,55 @@
+From 242bd6becd5cfaf0ffc77fc8b27c2e8db2c507e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 21 Jul 2024 19:18:58 +0530
+Subject: drm/amd/display: Add null check for head_pipe in
+ dcn201_acquire_free_pipe_for_layer
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit f22f4754aaa47d8c59f166ba3042182859e5dff7 ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn201_acquire_free_pipe_for_layer` function. The issue could occur
+when `head_pipe` is null.
+
+The fix adds a check to ensure `head_pipe` is not null before asserting
+it. If `head_pipe` is null, the function returns NULL to prevent a
+potential null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn201/dcn201_resource.c:1016 dcn201_acquire_free_pipe_for_layer() error: we previously assumed 'head_pipe' could be null (see line 1010)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c  | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
+index 070a4efb308bd..1aeede348bd39 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
+@@ -1005,8 +1005,10 @@ static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer(
+       struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream);
+       struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
+-      if (!head_pipe)
++      if (!head_pipe) {
+               ASSERT(0);
++              return NULL;
++      }
+       if (!idle_pipe)
+               return NULL;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch b/queue-6.10/drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch
new file mode 100644 (file)
index 0000000..34e68e8
--- /dev/null
@@ -0,0 +1,55 @@
+From 44d9709ea1656c2885dfaa4f08a73876aa1f1604 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 21 Jul 2024 19:30:16 +0530
+Subject: drm/amd/display: Add null check for head_pipe in
+ dcn32_acquire_idle_pipe_for_head_pipe_in_layer
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit ac2140449184a26eac99585b7f69814bd3ba8f2d ]
+
+This commit addresses a potential null pointer dereference issue in the
+`dcn32_acquire_idle_pipe_for_head_pipe_in_layer` function. The issue
+could occur when `head_pipe` is null.
+
+The fix adds a check to ensure `head_pipe` is not null before asserting
+it. If `head_pipe` is null, the function returns NULL to prevent a
+potential null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn32/dcn32_resource.c:2690 dcn32_acquire_idle_pipe_for_head_pipe_in_layer() error: we previously assumed 'head_pipe' could be null (see line 2681)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c    | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+index d84c8e0e5c2f0..9209bcad699a8 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+@@ -2664,8 +2664,10 @@ static struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
+       struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx;
+       int head_index;
+-      if (!head_pipe)
++      if (!head_pipe) {
+               ASSERT(0);
++              return NULL;
++      }
+       /*
+        * Modified from dcn20_acquire_idle_pipe_for_layer
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch b/queue-6.10/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch
new file mode 100644 (file)
index 0000000..297a050
--- /dev/null
@@ -0,0 +1,52 @@
+From 89d6ae7d67b12b481ea6f83a0c0dafb5c78f497d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 25 Jul 2024 07:23:48 +0530
+Subject: drm/amd/display: Add null check for top_pipe_to_program in
+ commit_planes_for_stream
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 66d71a72539e173a9b00ca0b1852cbaa5f5bf1ad ]
+
+This commit addresses a null pointer dereference issue in the
+`commit_planes_for_stream` function at line 4140. The issue could occur
+when `top_pipe_to_program` is null.
+
+The fix adds a check to ensure `top_pipe_to_program` is not null before
+accessing its stream_res. This prevents a null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc.c:4140 commit_planes_for_stream() error: we previously assumed 'top_pipe_to_program' could be null (see line 3906)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/core/dc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index da237f718dbdd..3bd18e862945f 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -3970,7 +3970,8 @@ static void commit_planes_for_stream(struct dc *dc,
+       }
+       if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
+-              if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
++              if (top_pipe_to_program &&
++                  top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
+                       top_pipe_to_program->stream_res.tg->funcs->wait_for_state(
+                               top_pipe_to_program->stream_res.tg,
+                               CRTC_STATE_VACTIVE);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch b/queue-6.10/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch
new file mode 100644 (file)
index 0000000..bdba7ce
--- /dev/null
@@ -0,0 +1,71 @@
+From 02f404fb3acce378df2c7923ee2e5976a7c854f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Jul 2024 09:17:56 -0600
+Subject: drm/amd/display: Avoid overflow assignment in link_dp_cts
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit a15268787b79fd183dd526cc16bec9af4f4e49a1 ]
+
+sampling_rate is an uint8_t but is assigned an unsigned int, and thus it
+can overflow. As a result, sampling_rate is changed to uint32_t.
+
+Similarly, LINK_QUAL_PATTERN_SET has a size of 2 bits, and it should
+only be assigned to a value less or equal than 4.
+
+This fixes 2 INTEGER_OVERFLOW issues reported by Coverity.
+
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-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/dc_dp_types.h                  | 2 +-
+ drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c | 3 ++-
+ drivers/gpu/drm/amd/display/include/dpcd_defs.h               | 1 +
+ 3 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+index 519c3df78ee5b..95c275bf649bd 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+@@ -727,7 +727,7 @@ struct dp_audio_test_data_flags {
+ struct dp_audio_test_data {
+       struct dp_audio_test_data_flags flags;
+-      uint8_t sampling_rate;
++      uint32_t sampling_rate;
+       uint8_t channel_count;
+       uint8_t pattern_type;
+       uint8_t pattern_period[8];
+diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
+index 8d1a1cc94a8b3..6b27ac56f60d8 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
++++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
+@@ -775,7 +775,8 @@ bool dp_set_test_pattern(
+                       core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
+                                           &training_pattern.raw,
+                                           sizeof(training_pattern));
+-                      training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
++                      if (pattern <= PHY_TEST_PATTERN_END_DP11)
++                              training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
+                       core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
+                                            &training_pattern.raw,
+                                            sizeof(training_pattern));
+diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+index aee5170f5fb23..c246235e4afec 100644
+--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
++++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+@@ -76,6 +76,7 @@ enum dpcd_phy_test_patterns {
+       PHY_TEST_PATTERN_D10_2,
+       PHY_TEST_PATTERN_SYMBOL_ERROR,
+       PHY_TEST_PATTERN_PRBS7,
++      PHY_TEST_PATTERN_END_DP11 = PHY_TEST_PATTERN_PRBS7,
+       PHY_TEST_PATTERN_80BIT_CUSTOM,/* For DP1.2 only */
+       PHY_TEST_PATTERN_CP2520_1,
+       PHY_TEST_PATTERN_CP2520_2,
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch b/queue-6.10/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch
new file mode 100644 (file)
index 0000000..13d59af
--- /dev/null
@@ -0,0 +1,54 @@
+From 6d43441908a3563e2d5a542156fbdad58e157e7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 16:45:39 -0600
+Subject: drm/amd/display: Check link_res->hpo_dp_link_enc before using it
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 0beca868cde8742240cd0038141c30482d2b7eb8 ]
+
+[WHAT & HOW]
+Functions dp_enable_link_phy and dp_disable_link_phy can pass link_res
+without initializing hpo_dp_link_enc and it is necessary to check for
+null before dereferencing.
+
+This fixes 2 FORWARD_NULL issues reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@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>
+---
+ .../gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c    | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
+index e1257404357b1..d0148f10dfc0a 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
+@@ -28,6 +28,8 @@
+ #include "dccg.h"
+ #include "clk_mgr.h"
++#define DC_LOGGER link->ctx->logger
++
+ void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+               struct fixed31_32 throttled_vcp_size)
+ {
+@@ -124,6 +126,11 @@ void disable_hpo_dp_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+ {
++      if (!link_res->hpo_dp_link_enc) {
++              DC_LOG_ERROR("%s: invalid hpo_dp_link_enc\n", __func__);
++              return;
++      }
++
+               link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
+               link_res->hpo_dp_link_enc->funcs->disable_link_phy(
+                               link_res->hpo_dp_link_enc, signal);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-check-null-initialized-variables.patch b/queue-6.10/drm-amd-display-check-null-initialized-variables.patch
new file mode 100644 (file)
index 0000000..7ed4821
--- /dev/null
@@ -0,0 +1,55 @@
+From dee3df10e147a8152d95b51c254228f0bb10367e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 17:34:18 -0600
+Subject: drm/amd/display: Check null-initialized variables
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 367cd9ceba1933b63bc1d87d967baf6d9fd241d2 ]
+
+[WHAT & HOW]
+drr_timing and subvp_pipe are initialized to null and they are not
+always assigned new values. It is necessary to check for null before
+dereferencing.
+
+This fixes 2 FORWARD_NULL issues reported by Coverity.
+
+Reviewed-by: Nevenko Stupar <nevenko.stupar@amd.com>
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@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>
+---
+ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+index ebcf5ece209a4..bf8c89fe95a7e 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -871,8 +871,9 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
+        * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
+        * and the max of (VBLANK blanking time, MALL region)).
+        */
+-      if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
+-                      subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
++      if (drr_timing &&
++          stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
++          subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
+               schedulable = true;
+       return schedulable;
+@@ -937,7 +938,7 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
+               if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN)
+                       subvp_pipe = pipe;
+       }
+-      if (found) {
++      if (found && subvp_pipe) {
+               phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream);
+               main_timing = &subvp_pipe->stream->timing;
+               phantom_timing = &phantom_stream->timing;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-check-null-pointers-before-using-dc-.patch b/queue-6.10/drm-amd-display-check-null-pointers-before-using-dc-.patch
new file mode 100644 (file)
index 0000000..3def87f
--- /dev/null
@@ -0,0 +1,46 @@
+From d08eb057942b3b212e05761baf51166bf77cd21f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 15:29:09 -0600
+Subject: drm/amd/display: Check null pointers before using dc->clk_mgr
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 95d9e0803e51d5a24276b7643b244c7477daf463 ]
+
+[WHY & HOW]
+dc->clk_mgr is null checked previously in the same function, indicating
+it might be null.
+
+Passing "dc" to "dc->hwss.apply_idle_power_optimizations", which
+dereferences null "dc->clk_mgr". (The function pointer resolves to
+"dcn35_apply_idle_power_optimizations".)
+
+This fixes 1 FORWARD_NULL issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Signed-off-by: Tom Chung <chiahsuan.chung@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>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
+index 3bd18e862945f..daeb80abf435f 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
+@@ -5211,7 +5211,8 @@ void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const
+       if (allow == dc->idle_optimizations_allowed)
+               return;
+-      if (dc->hwss.apply_idle_power_optimizations && dc->hwss.apply_idle_power_optimizations(dc, allow))
++      if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL &&
++          dc->hwss.apply_idle_power_optimizations(dc, allow))
+               dc->idle_optimizations_allowed = allow;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-check-null-pointers-before-using-the.patch b/queue-6.10/drm-amd-display-check-null-pointers-before-using-the.patch
new file mode 100644 (file)
index 0000000..8a6ada3
--- /dev/null
@@ -0,0 +1,66 @@
+From 7494a8c5a6b12d99e5176bc470b87b178f2bd9fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 17:38:16 -0600
+Subject: drm/amd/display: Check null pointers before using them
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 1ff12bcd7deaeed25efb5120433c6a45dd5504a8 ]
+
+[WHAT & HOW]
+These pointers are null checked previously in the same function,
+indicating they might be null as reported by Coverity. As a result,
+they need to be checked when used again.
+
+This fixes 3 FORWARD_NULL issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@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>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 3541d154cc8d0..9a578b1df141f 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -6951,6 +6951,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+       int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8;
+       enum dc_status dc_result = DC_OK;
++      if (!dm_state)
++              return NULL;
++
+       do {
+               stream = create_stream_for_sink(connector, drm_mode,
+                                               dm_state, old_stream,
+@@ -8963,7 +8966,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
+               if (acrtc)
+                       old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
+-              if (!acrtc->wb_enabled)
++              if (!acrtc || !acrtc->wb_enabled)
+                       continue;
+               dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+@@ -9362,9 +9365,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+                       DRM_INFO("[HDCP_DM] hdcp_update_display enable_encryption = %x\n", enable_encryption);
+-                      hdcp_update_display(
+-                              adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
+-                              new_con_state->hdcp_content_type, enable_encryption);
++                      if (aconnector->dc_link)
++                              hdcp_update_display(
++                                      adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
++                                      new_con_state->hdcp_content_type, enable_encryption);
+               }
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-check-phantom_stream-before-it-is-us.patch b/queue-6.10/drm-amd-display-check-phantom_stream-before-it-is-us.patch
new file mode 100644 (file)
index 0000000..5cb6a20
--- /dev/null
@@ -0,0 +1,41 @@
+From 6f9e87a4cc4aaa15e752a72084b86a6193dd4564 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Jun 2024 20:23:41 -0600
+Subject: drm/amd/display: Check phantom_stream before it is used
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 3718a619a8c0a53152e76bb6769b6c414e1e83f4 ]
+
+dcn32_enable_phantom_stream can return null, so returned value
+must be checked before used.
+
+This fixes 1 NULL_RETURNS issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@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>
+---
+ drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+index 9209bcad699a8..55fbe86383c04 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+@@ -1714,6 +1714,9 @@ void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context,
+       // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't
+       // already have phantom pipe assigned, etc.) by previous checks.
+       phantom_stream = dcn32_enable_phantom_stream(dc, context, pipes, pipe_cnt, index);
++      if (!phantom_stream)
++              return;
++
+       dcn32_enable_phantom_plane(dc, context, phantom_stream, index);
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-check-stream-before-comparing-them.patch b/queue-6.10/drm-amd-display-check-stream-before-comparing-them.patch
new file mode 100644 (file)
index 0000000..0ef909b
--- /dev/null
@@ -0,0 +1,41 @@
+From 3a9cb6560abc4458be1e1714180d74aef6d8227d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 20:05:14 -0600
+Subject: drm/amd/display: Check stream before comparing them
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 35ff747c86767937ee1e0ca987545b7eed7a0810 ]
+
+[WHAT & HOW]
+amdgpu_dm can pass a null stream to dc_is_stream_unchanged. It is
+necessary to check for null before dereferencing them.
+
+This fixes 1 FORWARD_NULL issue reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@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>
+---
+ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index 7462c34793799..58f6155fecc5a 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -3134,6 +3134,8 @@ static bool are_stream_backends_same(
+ bool dc_is_stream_unchanged(
+       struct dc_stream_state *old_stream, struct dc_stream_state *stream)
+ {
++      if (!old_stream || !stream)
++              return false;
+       if (!are_stream_backends_same(old_stream, stream))
+               return false;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch b/queue-6.10/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch
new file mode 100644 (file)
index 0000000..2ac1923
--- /dev/null
@@ -0,0 +1,79 @@
+From f586f182bb227a804c7b1da87eeabaae99407308 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 15 Aug 2024 18:45:22 -0400
+Subject: drm/amd/display: fix double free issue during amdgpu module unload
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit 20b5a8f9f4670a8503aa9fa95ca632e77c6bf55d ]
+
+Flexible endpoints use DIGs from available inflexible endpoints,
+so only the encoders of inflexible links need to be freed.
+Otherwise, a double free issue may occur when unloading the
+amdgpu module.
+
+[  279.190523] RIP: 0010:__slab_free+0x152/0x2f0
+[  279.190577] Call Trace:
+[  279.190580]  <TASK>
+[  279.190582]  ? show_regs+0x69/0x80
+[  279.190590]  ? die+0x3b/0x90
+[  279.190595]  ? do_trap+0xc8/0xe0
+[  279.190601]  ? do_error_trap+0x73/0xa0
+[  279.190605]  ? __slab_free+0x152/0x2f0
+[  279.190609]  ? exc_invalid_op+0x56/0x70
+[  279.190616]  ? __slab_free+0x152/0x2f0
+[  279.190642]  ? asm_exc_invalid_op+0x1f/0x30
+[  279.190648]  ? dcn10_link_encoder_destroy+0x19/0x30 [amdgpu]
+[  279.191096]  ? __slab_free+0x152/0x2f0
+[  279.191102]  ? dcn10_link_encoder_destroy+0x19/0x30 [amdgpu]
+[  279.191469]  kfree+0x260/0x2b0
+[  279.191474]  dcn10_link_encoder_destroy+0x19/0x30 [amdgpu]
+[  279.191821]  link_destroy+0xd7/0x130 [amdgpu]
+[  279.192248]  dc_destruct+0x90/0x270 [amdgpu]
+[  279.192666]  dc_destroy+0x19/0x40 [amdgpu]
+[  279.193020]  amdgpu_dm_fini+0x16e/0x200 [amdgpu]
+[  279.193432]  dm_hw_fini+0x26/0x40 [amdgpu]
+[  279.193795]  amdgpu_device_fini_hw+0x24c/0x400 [amdgpu]
+[  279.194108]  amdgpu_driver_unload_kms+0x4f/0x70 [amdgpu]
+[  279.194436]  amdgpu_pci_remove+0x40/0x80 [amdgpu]
+[  279.194632]  pci_device_remove+0x3a/0xa0
+[  279.194638]  device_remove+0x40/0x70
+[  279.194642]  device_release_driver_internal+0x1ad/0x210
+[  279.194647]  driver_detach+0x4e/0xa0
+[  279.194650]  bus_remove_driver+0x6f/0xf0
+[  279.194653]  driver_unregister+0x33/0x60
+[  279.194657]  pci_unregister_driver+0x44/0x90
+[  279.194662]  amdgpu_exit+0x19/0x1f0 [amdgpu]
+[  279.194939]  __do_sys_delete_module.isra.0+0x198/0x2f0
+[  279.194946]  __x64_sys_delete_module+0x16/0x20
+[  279.194950]  do_syscall_64+0x58/0x120
+[  279.194954]  entry_SYSCALL_64_after_hwframe+0x6e/0x76
+[  279.194980]  </TASK>
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Roman Li <roman.li@amd.com>
+Signed-off-by: Roman Li <roman.li@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>
+---
+ drivers/gpu/drm/amd/display/dc/link/link_factory.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+index 72df9bdfb23ff..608491f860b29 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+@@ -385,7 +385,7 @@ static void link_destruct(struct dc_link *link)
+       if (link->panel_cntl)
+               link->panel_cntl->funcs->destroy(&link->panel_cntl);
+-      if (link->link_enc) {
++      if (link->link_enc && !link->is_dig_mapping_flexible) {
+               /* Update link encoder resource tracking variables. These are used for
+                * the dynamic assignment of link encoders to streams. Virtual links
+                * are not assigned encoder resources on creation.
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch
new file mode 100644 (file)
index 0000000..01121e1
--- /dev/null
@@ -0,0 +1,54 @@
+From 8902693d3ceb14f9dcdf74c87347152bb229b481 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jul 2024 18:05:20 +0530
+Subject: drm/amd/display: Fix index out of bounds in DCN30 color
+ transformation
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit d81873f9e715b72d4f8d391c8eb243946f784dfc ]
+
+This commit addresses a potential index out of bounds issue in the
+`cm3_helper_translate_curve_to_hw_format` function in the DCN30 color
+management module. The issue could occur when the index 'i' exceeds the
+number of transfer function points (TRANSFER_FUNC_POINTS).
+
+The fix adds a check to ensure 'i' is within bounds before accessing the
+transfer function points. If 'i' is out of bounds, the function returns
+false to indicate an error.
+
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:180 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:181 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:182 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/dcn30/dcn30_cm_common.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+index edc77615d0973..0433f6b5dac78 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+@@ -177,6 +177,8 @@ bool cm3_helper_translate_curve_to_hw_format(
+                               i += increment) {
+                       if (j == hw_points)
+                               break;
++                      if (i >= TRANSFER_FUNC_POINTS)
++                              return false;
+                       rgb_resulted[j].red = output_tf->tf_pts.red[i];
+                       rgb_resulted[j].green = output_tf->tf_pts.green[i];
+                       rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch
new file mode 100644 (file)
index 0000000..1552598
--- /dev/null
@@ -0,0 +1,55 @@
+From 2637755aeaeef1b03c8b4cf994632c87e5da157c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jul 2024 18:44:02 +0530
+Subject: drm/amd/display: Fix index out of bounds in DCN30 degamma hardware
+ format translation
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit bc50b614d59990747dd5aeced9ec22f9258991ff ]
+
+This commit addresses a potential index out of bounds issue in the
+`cm3_helper_translate_curve_to_degamma_hw_format` function in the DCN30
+color  management module. The issue could occur when the index 'i'
+exceeds the  number of transfer function points (TRANSFER_FUNC_POINTS).
+
+The fix adds a check to ensure 'i' is within bounds before accessing the
+transfer function points. If 'i' is out of bounds, the function returns
+false to indicate an error.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:338 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:339 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:340 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/dcn30/dcn30_cm_common.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+index b8327237ed441..edc77615d0973 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+@@ -335,6 +335,8 @@ bool cm3_helper_translate_curve_to_degamma_hw_format(
+                               i += increment) {
+                       if (j == hw_points - 1)
+                               break;
++                      if (i >= TRANSFER_FUNC_POINTS)
++                              return false;
+                       rgb_resulted[j].red = output_tf->tf_pts.red[i];
+                       rgb_resulted[j].green = output_tf->tf_pts.green[i];
+                       rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch b/queue-6.10/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch
new file mode 100644 (file)
index 0000000..5a7797b
--- /dev/null
@@ -0,0 +1,55 @@
+From 90dce44ee6b6b61ee161f3818a2361651dfc7afe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Jul 2024 17:48:27 +0530
+Subject: drm/amd/display: Fix index out of bounds in degamma hardware format
+ translation
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit b7e99058eb2e86aabd7a10761e76cae33d22b49f ]
+
+Fixes index out of bounds issue in
+`cm_helper_translate_curve_to_degamma_hw_format` function. The issue
+could occur when the index 'i' exceeds the number of transfer function
+points (TRANSFER_FUNC_POINTS).
+
+The fix adds a check to ensure 'i' is within bounds before accessing the
+transfer function points. If 'i' is out of bounds the function returns
+false to indicate an error.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:594 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:595 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max
+drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:596 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/dcn10/dcn10_cm_common.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+index 0b49362f71b06..eaed5d1c398aa 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+@@ -591,6 +591,8 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
+                               i += increment) {
+                       if (j == hw_points - 1)
+                               break;
++                      if (i >= TRANSFER_FUNC_POINTS)
++                              return false;
+                       rgb_resulted[j].red = output_tf->tf_pts.red[i];
+                       rgb_resulted[j].green = output_tf->tf_pts.green[i];
+                       rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-handle-null-stream_status-in-planes_.patch b/queue-6.10/drm-amd-display-handle-null-stream_status-in-planes_.patch
new file mode 100644 (file)
index 0000000..27a7fea
--- /dev/null
@@ -0,0 +1,52 @@
+From 01bdb1d36092eae870d7dc4734deddbbe4546343 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 19:31:55 +0530
+Subject: drm/amd/display: Handle null 'stream_status' in
+ 'planes_changed_for_existing_stream'
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+[ Upstream commit 8141f21b941710ecebe49220b69822cab3abd23d ]
+
+This commit adds a null check for 'stream_status' in the function
+'planes_changed_for_existing_stream'. Previously, the code assumed
+'stream_status' could be null, but did not handle the case where it was
+actually null. This could lead to a null pointer dereference.
+
+Reported by smatch:
+drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_resource.c:3784 planes_changed_for_existing_stream() error: we previously assumed 'stream_status' could be null (see line 3774)
+
+Cc: Tom Chung <chiahsuan.chung@amd.com>
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Roman Li <roman.li@amd.com>
+Cc: Alex Hung <alex.hung@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Harry Wentland <harry.wentland@amd.com>
+Cc: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Tom Chung <chiahsuan.chung@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/core/dc_resource.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+index 786b56e96a816..7462c34793799 100644
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+@@ -3662,8 +3662,10 @@ static bool planes_changed_for_existing_stream(struct dc_state *context,
+               }
+       }
+-      if (!stream_status)
++      if (!stream_status) {
+               ASSERT(0);
++              return false;
++      }
+       for (i = 0; i < set_count; i++)
+               if (set[i].stream == stream)
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-initialize-get_bytes_per_element-s-d.patch b/queue-6.10/drm-amd-display-initialize-get_bytes_per_element-s-d.patch
new file mode 100644 (file)
index 0000000..49752f0
--- /dev/null
@@ -0,0 +1,55 @@
+From 15b6e650cb40bb877b553f7d0a30b8bd5dcc0b9a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Jul 2024 09:57:01 -0600
+Subject: drm/amd/display: Initialize get_bytes_per_element's default to 1
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 4067f4fa0423a89fb19a30b57231b384d77d2610 ]
+
+Variables, used as denominators and maybe not assigned to other values,
+should not be 0. bytes_per_element_y & bytes_per_element_c are
+initialized by get_bytes_per_element() which should never return 0.
+
+This fixes 10 DIVIDE_BY_ZERO issues reported by Coverity.
+
+Signed-off-by: Alex Hung <alex.hung@amd.com>
+Reviewed-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c | 2 +-
+ .../gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c   | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
+index 0fc9f3e3ffaef..f603486af6e30 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
+@@ -78,7 +78,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib,
+ static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma)
+ {
+-      unsigned int ret_val = 0;
++      unsigned int ret_val = 1;
+       if (source_format == dm_444_16) {
+               if (!is_chroma)
+diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
+index 618f4b682ab1b..9f28e4d3c664c 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
+@@ -53,7 +53,7 @@ static void calculate_ttu_cursor(
+ static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma)
+ {
+-      unsigned int ret_val = 0;
++      unsigned int ret_val = 1;
+       if (source_format == dm_444_16) {
+               if (!is_chroma)
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch b/queue-6.10/drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch
new file mode 100644 (file)
index 0000000..75c7cfa
--- /dev/null
@@ -0,0 +1,73 @@
+From 10aa1c246de785f2329bb0ce0f95800c224d2a80 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Jun 2024 11:51:27 -0600
+Subject: drm/amd/display: Pass non-null to
+ dcn20_validate_apply_pipe_split_flags
+
+From: Alex Hung <alex.hung@amd.com>
+
+[ Upstream commit 5559598742fb4538e4c51c48ef70563c49c2af23 ]
+
+[WHAT & HOW]
+"dcn20_validate_apply_pipe_split_flags" dereferences merge, and thus it
+cannot be a null pointer. Let's pass a valid pointer to avoid null
+dereference.
+
+This fixes 2 FORWARD_NULL issues reported by Coverity.
+
+Reviewed-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Jerry Zuo <jerry.zuo@amd.com>
+Signed-off-by: Alex Hung <alex.hung@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>
+---
+ drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c | 3 ++-
+ drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+index 6b380e037e3f8..c0d1b41eb9004 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+@@ -2033,6 +2033,7 @@ bool dcn20_fast_validate_bw(
+ {
+       bool out = false;
+       int split[MAX_PIPES] = { 0 };
++      bool merge[MAX_PIPES] = { false };
+       int pipe_cnt, i, pipe_idx, vlevel;
+       ASSERT(pipes);
+@@ -2057,7 +2058,7 @@ bool dcn20_fast_validate_bw(
+       if (vlevel > context->bw_ctx.dml.soc.num_states)
+               goto validate_fail;
+-      vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL);
++      vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
+       /*initialize pipe_just_split_from to invalid idx*/
+       for (i = 0; i < MAX_PIPES; i++)
+diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+index 8663cbc3d1cf5..347e6aaea582f 100644
+--- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+@@ -774,6 +774,7 @@ bool dcn21_fast_validate_bw(struct dc *dc,
+ {
+       bool out = false;
+       int split[MAX_PIPES] = { 0 };
++      bool merge[MAX_PIPES] = { false };
+       int pipe_cnt, i, pipe_idx, vlevel;
+       ASSERT(pipes);
+@@ -816,7 +817,7 @@ bool dcn21_fast_validate_bw(struct dc *dc,
+                       goto validate_fail;
+       }
+-      vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL);
++      vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
+       for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch b/queue-6.10/drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch
new file mode 100644 (file)
index 0000000..3028488
--- /dev/null
@@ -0,0 +1,96 @@
+From 74cb516c5ef321e3636b64783a42545f4c3a975c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 11:53:31 -0400
+Subject: drm/amd/display: Use gpuvm_min_page_size_kbytes for DML2 surfaces
+
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+
+[ Upstream commit 31663521ede2edb622ee1b397ae3ac666d6351c5 ]
+
+[Why]
+It's currently hard coded to 256 when it should be using the SOC
+provided values. This can result in corruption with linear surfaces
+where we prefetch more PTE than the buffer can hold.
+
+[How]
+Update the min page size correctly for the plane.
+
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Reviewed-by: Jun Lei <jun.lei@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../display/dc/dml2/dml2_translation_helper.c | 20 +++++++++++++------
+ 1 file changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
+index edff6b447680c..d5dbfb33f93dc 100644
+--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
++++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
+@@ -828,7 +828,9 @@ static void get_scaler_data_for_plane(const struct dc_plane_state *in, struct dc
+       memcpy(out, &temp_pipe->plane_res.scl_data, sizeof(*out));
+ }
+-static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_stream_state *in)
++static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location,
++                                       const struct dc_stream_state *in,
++                                       const struct soc_bounding_box_st *soc)
+ {
+       dml_uint_t width, height;
+@@ -845,7 +847,7 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned
+       out->CursorBPP[location] = dml_cur_32bit;
+       out->CursorWidth[location] = 256;
+-      out->GPUVMMinPageSizeKBytes[location] = 256;
++      out->GPUVMMinPageSizeKBytes[location] = soc->gpuvm_min_page_size_kbytes;
+       out->ViewportWidth[location] = width;
+       out->ViewportHeight[location] = height;
+@@ -882,7 +884,9 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned
+       out->ScalerEnabled[location] = false;
+ }
+-static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_plane_state *in, struct dc_state *context)
++static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out, unsigned int location,
++                                                  const struct dc_plane_state *in, struct dc_state *context,
++                                                  const struct soc_bounding_box_st *soc)
+ {
+       struct scaler_data *scaler_data = kzalloc(sizeof(*scaler_data), GFP_KERNEL);
+       if (!scaler_data)
+@@ -893,7 +897,7 @@ static void populate_dml_plane_cfg_from_plane_state(struct dml_plane_cfg_st *out
+       out->CursorBPP[location] = dml_cur_32bit;
+       out->CursorWidth[location] = 256;
+-      out->GPUVMMinPageSizeKBytes[location] = 256;
++      out->GPUVMMinPageSizeKBytes[location] = soc->gpuvm_min_page_size_kbytes;
+       out->ViewportWidth[location] = scaler_data->viewport.width;
+       out->ViewportHeight[location] = scaler_data->viewport.height;
+@@ -1174,7 +1178,8 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat
+                       disp_cfg_plane_location = dml_dispcfg->num_surfaces++;
+                       populate_dummy_dml_surface_cfg(&dml_dispcfg->surface, disp_cfg_plane_location, context->streams[i]);
+-                      populate_dummy_dml_plane_cfg(&dml_dispcfg->plane, disp_cfg_plane_location, context->streams[i]);
++                      populate_dummy_dml_plane_cfg(&dml_dispcfg->plane, disp_cfg_plane_location,
++                                                   context->streams[i], &dml2->v20.dml_core_ctx.soc);
+                       dml_dispcfg->plane.BlendingAndTiming[disp_cfg_plane_location] = disp_cfg_stream_location;
+@@ -1190,7 +1195,10 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat
+                               ASSERT(disp_cfg_plane_location >= 0 && disp_cfg_plane_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__);
+                               populate_dml_surface_cfg_from_plane_state(dml2->v20.dml_core_ctx.project, &dml_dispcfg->surface, disp_cfg_plane_location, context->stream_status[i].plane_states[j]);
+-                              populate_dml_plane_cfg_from_plane_state(&dml_dispcfg->plane, disp_cfg_plane_location, context->stream_status[i].plane_states[j], context);
++                              populate_dml_plane_cfg_from_plane_state(
++                                      &dml_dispcfg->plane, disp_cfg_plane_location,
++                                      context->stream_status[i].plane_states[j], context,
++                                      &dml2->v20.dml_core_ctx.soc);
+                               if (stream_mall_type == SUBVP_MAIN) {
+                                       dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_sub_viewport;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch b/queue-6.10/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch
new file mode 100644 (file)
index 0000000..02fdeaf
--- /dev/null
@@ -0,0 +1,36 @@
+From fdead484e49c95c4bee7f8ca05eaf73092532e90 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 17:15:12 +0800
+Subject: drm/amd/pm: ensure the fw_info is not null before using it
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit 186fb12e7a7b038c2710ceb2fb74068f1b5d55a4 ]
+
+This resolves the dereference null return value warning
+reported by Coverity.
+
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Jesse Zhang <jesse.zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
+index 5794b64507bf9..56a2257525806 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
+@@ -1185,6 +1185,8 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
+       fw_info = smu_atom_get_data_table(hwmgr->adev,
+                        GetIndexIntoMasterTable(DATA, FirmwareInfo),
+                        &size, &frev, &crev);
++      PP_ASSERT_WITH_CODE(fw_info != NULL,
++                          "Missing firmware info!", return -EINVAL);
+       if ((fw_info->ucTableFormatRevision == 1)
+           && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch b/queue-6.10/drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch
new file mode 100644 (file)
index 0000000..652e4da
--- /dev/null
@@ -0,0 +1,61 @@
+From eca008855174ca03f598be20cc15d16391300e7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 14:42:41 +0800
+Subject: drm/amdgpu: add list empty check to avoid null pointer issue
+
+From: Yang Wang <kevinyang.wang@amd.com>
+
+[ Upstream commit 4416377ae1fdc41a90b665943152ccd7ff61d3c5 ]
+
+Add list empty check to avoid null pointer issues in some corner cases.
+- list_for_each_entry_safe()
+
+Signed-off-by: Yang Wang <kevinyang.wang@amd.com>
+Reviewed-by: Tao Zhou <tao.zhou1@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_aca.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+index 9baee7c246b6d..a513819b72311 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+@@ -80,6 +80,9 @@ static void aca_banks_release(struct aca_banks *banks)
+ {
+       struct aca_bank_node *node, *tmp;
++      if (list_empty(&banks->list))
++              return;
++
+       list_for_each_entry_safe(node, tmp, &banks->list, node) {
+               list_del(&node->node);
+               kvfree(node);
+@@ -562,9 +565,13 @@ static void aca_error_fini(struct aca_error *aerr)
+       struct aca_bank_error *bank_error, *tmp;
+       mutex_lock(&aerr->lock);
++      if (list_empty(&aerr->list))
++              goto out_unlock;
++
+       list_for_each_entry_safe(bank_error, tmp, &aerr->list, node)
+               aca_bank_error_remove(aerr, bank_error);
++out_unlock:
+       mutex_destroy(&aerr->lock);
+ }
+@@ -680,6 +687,9 @@ static void aca_manager_fini(struct aca_handle_manager *mgr)
+ {
+       struct aca_handle *handle, *tmp;
++      if (list_empty(&mgr->list))
++              return;
++
+       list_for_each_entry_safe(handle, tmp, &mgr->list, node)
+               amdgpu_aca_remove_handle(handle);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-add-raven1-gfxoff-quirk.patch b/queue-6.10/drm-amdgpu-add-raven1-gfxoff-quirk.patch
new file mode 100644 (file)
index 0000000..27e4540
--- /dev/null
@@ -0,0 +1,35 @@
+From 3c9741dcf701d420303ebaa8105a889b62b35d0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Aug 2024 15:25:54 +0800
+Subject: drm/amdgpu: add raven1 gfxoff quirk
+
+From: Peng Liu <liupeng01@kylinos.cn>
+
+[ Upstream commit 0126c0ae11e8b52ecfde9d1b174ee2f32d6c3a5d ]
+
+Fix screen corruption with openkylin.
+
+Link: https://bbs.openkylin.top/t/topic/171497
+Signed-off-by: Peng Liu <liupeng01@kylinos.cn>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index 3c8c5abf35abd..c86a6363b2c3d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -1172,6 +1172,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = {
+       { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc6 },
+       /* Apple MacBook Pro (15-inch, 2019) Radeon Pro Vega 20 4 GB */
+       { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 },
++      /* https://bbs.openkylin.top/t/topic/171497 */
++      { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 },
+       { 0, 0, 0, 0, 0 },
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch b/queue-6.10/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch
new file mode 100644 (file)
index 0000000..5876500
--- /dev/null
@@ -0,0 +1,111 @@
+From f284b9fcbd8c159d528a7ecff7e5ee4e9d5df29e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 13:40:23 -0400
+Subject: drm/amdgpu: Block MMR_READ IOCTL in reset
+
+From: Victor Skvortsov <victor.skvortsov@amd.com>
+
+[ Upstream commit 9e823f307074c0f82b5f6044943b0086e3079bed ]
+
+Register access from userspace should be blocked until
+reset is complete.
+
+Signed-off-by: Victor Skvortsov <victor.skvortsov@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_kms.c | 43 ++++++++++++++++++-------
+ 1 file changed, 31 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+index 977cde6d13626..6d4e774b6cedc 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+@@ -43,6 +43,7 @@
+ #include "amdgpu_gem.h"
+ #include "amdgpu_display.h"
+ #include "amdgpu_ras.h"
++#include "amdgpu_reset.h"
+ #include "amd_pcie.h"
+ void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev)
+@@ -778,6 +779,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+                                   ? -EFAULT : 0;
+       }
+       case AMDGPU_INFO_READ_MMR_REG: {
++              int ret = 0;
+               unsigned int n, alloc_size;
+               uint32_t *regs;
+               unsigned int se_num = (info->read_mmr_reg.instance >>
+@@ -787,24 +789,37 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+                                  AMDGPU_INFO_MMR_SH_INDEX_SHIFT) &
+                                 AMDGPU_INFO_MMR_SH_INDEX_MASK;
++              if (!down_read_trylock(&adev->reset_domain->sem))
++                      return -ENOENT;
++
+               /* set full masks if the userspace set all bits
+                * in the bitfields
+                */
+-              if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
++              if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) {
+                       se_num = 0xffffffff;
+-              else if (se_num >= AMDGPU_GFX_MAX_SE)
+-                      return -EINVAL;
+-              if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
++              } else if (se_num >= AMDGPU_GFX_MAX_SE) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++
++              if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) {
+                       sh_num = 0xffffffff;
+-              else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE)
+-                      return -EINVAL;
++              } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) {
++                      ret = -EINVAL;
++                      goto out;
++              }
+-              if (info->read_mmr_reg.count > 128)
+-                      return -EINVAL;
++              if (info->read_mmr_reg.count > 128) {
++                      ret = -EINVAL;
++                      goto out;
++              }
+               regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL);
+-              if (!regs)
+-                      return -ENOMEM;
++              if (!regs) {
++                      ret = -ENOMEM;
++                      goto out;
++              }
++
+               alloc_size = info->read_mmr_reg.count * sizeof(*regs);
+               amdgpu_gfx_off_ctrl(adev, false);
+@@ -816,13 +831,17 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+                                             info->read_mmr_reg.dword_offset + i);
+                               kfree(regs);
+                               amdgpu_gfx_off_ctrl(adev, true);
+-                              return -EFAULT;
++                              ret = -EFAULT;
++                              goto out;
+                       }
+               }
+               amdgpu_gfx_off_ctrl(adev, true);
+               n = copy_to_user(out, regs, min(size, alloc_size));
+               kfree(regs);
+-              return n ? -EFAULT : 0;
++              ret = (n ? -EFAULT : 0);
++out:
++              up_read(&adev->reset_domain->sem);
++              return ret;
+       }
+       case AMDGPU_INFO_DEV_INFO: {
+               struct drm_amdgpu_info_device *dev_info;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch b/queue-6.10/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch
new file mode 100644 (file)
index 0000000..1c8f505
--- /dev/null
@@ -0,0 +1,49 @@
+From ea14f7e443375ce5354949f73febe7aa27e3fdaf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Jul 2024 11:54:30 +0200
+Subject: drm/amdgpu: disallow multiple BO_HANDLES chunks in one submit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
+
+[ Upstream commit fec5f8e8c6bcf83ed7a392801d7b44c5ecfc1e82 ]
+
+Before this commit, only submits with both a BO_HANDLES chunk and a
+'bo_list_handle' would be rejected (by amdgpu_cs_parser_bos).
+
+But if UMD sent multiple BO_HANDLES, what would happen is:
+* only the last one would be really used
+* all the others would leak memory as amdgpu_cs_p1_bo_handles would
+  overwrite the previous p->bo_list value
+
+This commit rejects submissions with multiple BO_HANDLES chunks to
+match the implementation of the parser.
+
+Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
+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_cs.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+index 6dfdff58bffd1..78b3c067fea7e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -263,6 +263,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
+                       if (size < sizeof(struct drm_amdgpu_bo_list_in))
+                               goto free_partial_kdata;
++                      /* Only a single BO list is allowed to simplify handling. */
++                      if (p->bo_list)
++                              ret = -EINVAL;
++
+                       ret = amdgpu_cs_p1_bo_handles(p, p->chunks[i].kdata);
+                       if (ret)
+                               goto free_partial_kdata;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch b/queue-6.10/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch
new file mode 100644 (file)
index 0000000..7375fd5
--- /dev/null
@@ -0,0 +1,38 @@
+From ab9c7b50eb4002c898db893d88c71083de991104 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Aug 2024 15:27:08 +0800
+Subject: drm/amdgpu: enable gfxoff quirk on HP 705G4
+
+From: Peng Liu <liupeng01@kylinos.cn>
+
+[ Upstream commit 2c7795e245d993bcba2f716a8c93a5891ef910c9 ]
+
+Enabling gfxoff quirk results in perfectly usable
+graphical user interface on HP 705G4 DM with R5 2400G.
+
+Without the quirk, X server is completely unusable as
+every few seconds there is gpu reset due to ring gfx timeout.
+
+Signed-off-by: Peng Liu <liupeng01@kylinos.cn>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index c86a6363b2c3d..0594eab666a9b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -1174,6 +1174,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = {
+       { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 },
+       /* https://bbs.openkylin.top/t/topic/171497 */
+       { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 },
++      /* HP 705G4 DM with R5 2400G */
++      { 0x1002, 0x15dd, 0x103c, 0x8464, 0xd6 },
+       { 0, 0, 0, 0, 0 },
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch b/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch
new file mode 100644 (file)
index 0000000..d927c25
--- /dev/null
@@ -0,0 +1,72 @@
+From d7726729a2100aaf7a1070454c2df1ffb28dddcf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 10:38:37 +0800
+Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_gfx
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit c0277b9d7c2ee9ee5dbc948548984f0fbb861301 ]
+
+This resolves the unchecded return value warning reported by Coverity.
+
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Jesse Zhang <jesse.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_gfx.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+index e92bdc9a39d35..1935b211b527d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+@@ -816,8 +816,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
+       int r;
+       if (amdgpu_ras_is_supported(adev, ras_block->block)) {
+-              if (!amdgpu_persistent_edc_harvesting_supported(adev))
+-                      amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX);
++              if (!amdgpu_persistent_edc_harvesting_supported(adev)) {
++                      r = amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX);
++                      if (r)
++                              return r;
++              }
+               r = amdgpu_ras_block_late_init(adev, ras_block);
+               if (r)
+@@ -961,7 +964,10 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg, uint32_t xcc_
+               pr_err("critical bug! too many kiq readers\n");
+               goto failed_unlock;
+       }
+-      amdgpu_ring_alloc(ring, 32);
++      r = amdgpu_ring_alloc(ring, 32);
++      if (r)
++              goto failed_unlock;
++
+       amdgpu_ring_emit_rreg(ring, reg, reg_val_offs);
+       r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT);
+       if (r)
+@@ -1027,7 +1033,10 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3
+       }
+       spin_lock_irqsave(&kiq->ring_lock, flags);
+-      amdgpu_ring_alloc(ring, 32);
++      r = amdgpu_ring_alloc(ring, 32);
++      if (r)
++              goto failed_unlock;
++
+       amdgpu_ring_emit_wreg(ring, reg, v);
+       r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT);
+       if (r)
+@@ -1063,6 +1072,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v, uint3
+ failed_undo:
+       amdgpu_ring_undo(ring);
++failed_unlock:
+       spin_unlock_irqrestore(&kiq->ring_lock, flags);
+ failed_kiq_write:
+       dev_err(adev->dev, "failed to write reg:%x\n", reg);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177 b/queue-6.10/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177
new file mode 100644 (file)
index 0000000..1f16eb4
--- /dev/null
@@ -0,0 +1,110 @@
+From c41c7229251589c515b35d1cad324ace9059fb3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 13:47:55 +0800
+Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_atombios
+
+From: Tim Huang <tim.huang@amd.com>
+
+[ Upstream commit 92549780e32718d64a6d08bbbb3c6fffecb541c7 ]
+
+This resolves the unchecded return value warning reported by Coverity.
+
+Signed-off-by: Tim Huang <tim.huang@amd.com>
+Reviewed-by: Jesse Zhang <jesse.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_atombios.c | 35 ++++++++++++--------
+ 1 file changed, 21 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+index 7dc102f0bc1d3..0c8975ac5af9e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+@@ -1018,8 +1018,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+               if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
+                       args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
+-                      amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                              sizeof(args));
++                      if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                          index, (uint32_t *)&args, sizeof(args)))
++                              return -EINVAL;
+                       dividers->post_div = args.v3.ucPostDiv;
+                       dividers->enable_post_div = (args.v3.ucCntlFlag &
+@@ -1039,8 +1040,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+                       if (strobe_mode)
+                               args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
+-                      amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                              sizeof(args));
++                      if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                          index, (uint32_t *)&args, sizeof(args)))
++                              return -EINVAL;
+                       dividers->post_div = args.v5.ucPostDiv;
+                       dividers->enable_post_div = (args.v5.ucCntlFlag &
+@@ -1058,8 +1060,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+               /* fusion */
+               args.v4.ulClock = cpu_to_le32(clock);   /* 10 khz */
+-              amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                      sizeof(args));
++              if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                  index, (uint32_t *)&args, sizeof(args)))
++                      return -EINVAL;
+               dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
+               dividers->real_clock = le32_to_cpu(args.v4.ulClock);
+@@ -1070,8 +1073,9 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+               args.v6_in.ulClock.ulComputeClockFlag = clock_type;
+               args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock);    /* 10 khz */
+-              amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                      sizeof(args));
++              if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                  index, (uint32_t *)&args, sizeof(args)))
++                      return -EINVAL;
+               dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
+               dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
+@@ -1113,8 +1117,9 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,
+                       if (strobe_mode)
+                               args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;
+-                      amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                              sizeof(args));
++                      if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                          index, (uint32_t *)&args, sizeof(args)))
++                              return -EINVAL;
+                       mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);
+                       mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);
+@@ -1211,8 +1216,9 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
+               args.v2.ucVoltageMode = 0;
+               args.v2.usVoltageLevel = 0;
+-              amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                      sizeof(args));
++              if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                  index, (uint32_t *)&args, sizeof(args)))
++                      return -EINVAL;
+               *voltage = le16_to_cpu(args.v2.usVoltageLevel);
+               break;
+@@ -1221,8 +1227,9 @@ int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
+               args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
+               args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
+-              amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args,
+-                      sizeof(args));
++              if (amdgpu_atom_execute_table(adev->mode_info.atom_context,
++                  index, (uint32_t *)&args, sizeof(args)))
++                      return -EINVAL;
+               *voltage = le16_to_cpu(args.v3.usVoltageLevel);
+               break;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.10/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch
new file mode 100644 (file)
index 0000000..4a43894
--- /dev/null
@@ -0,0 +1,35 @@
+From d48d9048adce8926942b9f7750a67aefb6825b9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jul 2024 18:20:34 -0400
+Subject: drm/amdgpu/gfx10: use rlc safe mode for soft recovery
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit ead60e9c4e29c8574cae1be4fe3af1d9a978fb0f ]
+
+Protect the MMIO access with safe mode.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+index 536287ddd2ec1..6204336750c6a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+@@ -8897,7 +8897,9 @@ static void gfx_v10_0_ring_soft_recovery(struct amdgpu_ring *ring,
+       value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
+       value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
+       value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
++      amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+       WREG32_SOC15(GC, 0, mmSQ_CMD, value);
++      amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+ }
+ static void
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch b/queue-6.10/drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch
new file mode 100644 (file)
index 0000000..333e84c
--- /dev/null
@@ -0,0 +1,43 @@
+From eefee339f47697cbe172d60ee24a5d5d2fb5fd76 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jul 2024 15:36:19 -0400
+Subject: drm/amdgpu/gfx11: enter safe mode before touching CP_INT_CNTL
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit b5be054c585110b2c5c1b180136800e8c41c7bb4 ]
+
+Need to enter safe mode before touching GC MMIO.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+index 4ba8eb45ac174..0bcdcb2101577 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -4497,6 +4497,8 @@ static int gfx_v11_0_soft_reset(void *handle)
+       int r, i, j, k;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
++      gfx_v11_0_set_safe_mode(adev, 0);
++
+       tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CMP_BUSY_INT_ENABLE, 0);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, CNTX_BUSY_INT_ENABLE, 0);
+@@ -4504,8 +4506,6 @@ static int gfx_v11_0_soft_reset(void *handle)
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL, GFX_IDLE_INT_ENABLE, 0);
+       WREG32_SOC15(GC, 0, regCP_INT_CNTL, tmp);
+-      gfx_v11_0_set_safe_mode(adev, 0);
+-
+       mutex_lock(&adev->srbm_mutex);
+       for (i = 0; i < adev->gfx.mec.num_mec; ++i) {
+               for (j = 0; j < adev->gfx.mec.num_queue_per_pipe; j++) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.10/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch
new file mode 100644 (file)
index 0000000..1a4d413
--- /dev/null
@@ -0,0 +1,35 @@
+From 06d094709cb66935ac8de8a0326a3f7913eb4679 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jul 2024 18:20:23 -0400
+Subject: drm/amdgpu/gfx11: use rlc safe mode for soft recovery
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 3f2d35c325534c1b7ac5072173f0dc7ca969dec2 ]
+
+Protect the MMIO access with safe mode.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+index 0bcdcb2101577..6b5cd0dcd25f4 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -5792,7 +5792,9 @@ static void gfx_v11_0_ring_soft_recovery(struct amdgpu_ring *ring,
+       value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
+       value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
+       value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
++      amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+       WREG32_SOC15(GC, 0, regSQ_CMD, value);
++      amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+ }
+ static void
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch b/queue-6.10/drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch
new file mode 100644 (file)
index 0000000..72097a0
--- /dev/null
@@ -0,0 +1,170 @@
+From 1b9adcb5f75046d24e96ecb4815fcead7e371fd6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Jul 2024 10:24:59 -0400
+Subject: drm/amdgpu/gfx9: properly handle error ints on all pipes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 48695573d2feaf42812c1ad54e01caff0d1c2d71 ]
+
+Need to handle the interrupt enables for all pipes.
+
+Acked-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/gfx_v9_0.c   | 44 +++++++++++++++++++++-
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 50 +++++++++++++++++++++++--
+ 2 files changed, 89 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index 0594eab666a9b..b278453cad6d4 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -2477,7 +2477,7 @@ static void gfx_v9_0_enable_gui_idle_interrupt(struct amdgpu_device *adev,
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE, enable ? 1 : 0);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CNTX_EMPTY_INT_ENABLE, enable ? 1 : 0);
+       tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, CMP_BUSY_INT_ENABLE, enable ? 1 : 0);
+-      if(adev->gfx.num_gfx_rings)
++      if (adev->gfx.num_gfx_rings)
+               tmp = REG_SET_FIELD(tmp, CP_INT_CNTL_RING0, GFX_IDLE_INT_ENABLE, enable ? 1 : 0);
+       WREG32_SOC15(GC, 0, mmCP_INT_CNTL_RING0, tmp);
+@@ -5772,17 +5772,59 @@ static void gfx_v9_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev,
+       }
+ }
++static u32 gfx_v9_0_get_cpc_int_cntl(struct amdgpu_device *adev,
++                                   int me, int pipe)
++{
++      /*
++       * amdgpu controls only the first MEC. That's why this function only
++       * handles the setting of interrupts for this specific MEC. All other
++       * pipes' interrupts are set by amdkfd.
++       */
++      if (me != 1)
++              return 0;
++
++      switch (pipe) {
++      case 0:
++              return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE0_INT_CNTL);
++      case 1:
++              return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE1_INT_CNTL);
++      case 2:
++              return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE2_INT_CNTL);
++      case 3:
++              return SOC15_REG_OFFSET(GC, 0, mmCP_ME1_PIPE3_INT_CNTL);
++      default:
++              return 0;
++      }
++}
++
+ static int gfx_v9_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
+                                            struct amdgpu_irq_src *source,
+                                            unsigned type,
+                                            enum amdgpu_interrupt_state state)
+ {
++      u32 cp_int_cntl_reg, cp_int_cntl;
++      int i, j;
++
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+       case AMDGPU_IRQ_STATE_ENABLE:
+               WREG32_FIELD15(GC, 0, CP_INT_CNTL_RING0,
+                              PRIV_REG_INT_ENABLE,
+                              state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++              for (i = 0; i < adev->gfx.mec.num_mec; i++) {
++                      for (j = 0; j < adev->gfx.mec.num_pipe_per_mec; j++) {
++                              /* MECs start at 1 */
++                              cp_int_cntl_reg = gfx_v9_0_get_cpc_int_cntl(adev, i + 1, j);
++
++                              if (cp_int_cntl_reg) {
++                                      cp_int_cntl = RREG32_SOC15_IP(GC, cp_int_cntl_reg);
++                                      cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_ME1_PIPE0_INT_CNTL,
++                                                                  PRIV_REG_INT_ENABLE,
++                                                                  state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++                                      WREG32_SOC15_IP(GC, cp_int_cntl_reg, cp_int_cntl);
++                              }
++                      }
++              }
+               break;
+       default:
+               break;
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+index f5b9f443cfdd7..2564a003526ae 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+@@ -2824,21 +2824,63 @@ static void gfx_v9_4_3_xcc_set_compute_eop_interrupt_state(
+       }
+ }
++static u32 gfx_v9_4_3_get_cpc_int_cntl(struct amdgpu_device *adev,
++                                   int xcc_id, int me, int pipe)
++{
++      /*
++       * amdgpu controls only the first MEC. That's why this function only
++       * handles the setting of interrupts for this specific MEC. All other
++       * pipes' interrupts are set by amdkfd.
++       */
++      if (me != 1)
++              return 0;
++
++      switch (pipe) {
++      case 0:
++              return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE0_INT_CNTL);
++      case 1:
++              return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE1_INT_CNTL);
++      case 2:
++              return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE2_INT_CNTL);
++      case 3:
++              return SOC15_REG_OFFSET(GC, GET_INST(GC, xcc_id), regCP_ME1_PIPE3_INT_CNTL);
++      default:
++              return 0;
++      }
++}
++
+ static int gfx_v9_4_3_set_priv_reg_fault_state(struct amdgpu_device *adev,
+                                            struct amdgpu_irq_src *source,
+                                            unsigned type,
+                                            enum amdgpu_interrupt_state state)
+ {
+-      int i, num_xcc;
++      u32 mec_int_cntl_reg, mec_int_cntl;
++      int i, j, k, num_xcc;
+       num_xcc = NUM_XCC(adev->gfx.xcc_mask);
+       switch (state) {
+       case AMDGPU_IRQ_STATE_DISABLE:
+       case AMDGPU_IRQ_STATE_ENABLE:
+-              for (i = 0; i < num_xcc; i++)
++              for (i = 0; i < num_xcc; i++) {
+                       WREG32_FIELD15_PREREG(GC, GET_INST(GC, i), CP_INT_CNTL_RING0,
+-                              PRIV_REG_INT_ENABLE,
+-                              state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++                                            PRIV_REG_INT_ENABLE,
++                                            state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
++                      for (j = 0; j < adev->gfx.mec.num_mec; j++) {
++                              for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; k++) {
++                                      /* MECs start at 1 */
++                                      mec_int_cntl_reg = gfx_v9_4_3_get_cpc_int_cntl(adev, i, j + 1, k);
++
++                                      if (mec_int_cntl_reg) {
++                                              mec_int_cntl = RREG32_XCC(mec_int_cntl_reg, i);
++                                              mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL,
++                                                                           PRIV_REG_INT_ENABLE,
++                                                                           state == AMDGPU_IRQ_STATE_ENABLE ?
++                                                                           1 : 0);
++                                              WREG32_XCC(mec_int_cntl_reg, mec_int_cntl, i);
++                                      }
++                              }
++                      }
++              }
+               break;
+       default:
+               break;
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.10/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch
new file mode 100644 (file)
index 0000000..681d552
--- /dev/null
@@ -0,0 +1,35 @@
+From 3716fb348cb9d34ac5f1b89456fa9d236a417a5d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Jul 2024 18:20:57 -0400
+Subject: drm/amdgpu/gfx9: use rlc safe mode for soft recovery
+
+From: Alex Deucher <alexander.deucher@amd.com>
+
+[ Upstream commit 3ec2ad7c34c412bd9264cd1ff235d0812be90e82 ]
+
+Protect the MMIO access with safe mode.
+
+Acked-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index b278453cad6d4..d8d3d2c93d8ee 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -5701,7 +5701,9 @@ static void gfx_v9_0_ring_soft_recovery(struct amdgpu_ring *ring, unsigned vmid)
+       value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01);
+       value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1);
+       value = REG_SET_FIELD(value, SQ_CMD, VM_ID, vmid);
++      amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+       WREG32_SOC15(GC, 0, mmSQ_CMD, value);
++      amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+ }
+ static void gfx_v9_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch b/queue-6.10/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch
new file mode 100644 (file)
index 0000000..14dde34
--- /dev/null
@@ -0,0 +1,165 @@
+From 05572408f8d9c5e60c1df8fb8cf409c825533f62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Jul 2024 11:11:05 -0400
+Subject: drm/amdkfd: amdkfd_free_gtt_mem clear the correct pointer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Philip Yang <Philip.Yang@amd.com>
+
+[ Upstream commit c86ad39140bbcb9dc75a10046c2221f657e8083b ]
+
+Pass pointer reference to amdgpu_bo_unref to clear the correct pointer,
+otherwise amdgpu_bo_unref clear the local variable, the original pointer
+not set to NULL, this could cause use-after-free bug.
+
+Signed-off-by: Philip Yang <Philip.Yang@amd.com>
+Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
+Acked-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_amdkfd.c         | 14 +++++++-------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h         |  2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c           |  2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_device.c            |  4 ++--
+ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c  |  2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c       |  2 +-
+ drivers/gpu/drm/amd/amdkfd/kfd_process.c           |  2 +-
+ .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c |  4 ++--
+ 8 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+index e3738d4172458..26ecca3e8e900 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+@@ -360,15 +360,15 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size,
+       return r;
+ }
+-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj)
++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj)
+ {
+-      struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj;
++      struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj;
+-      amdgpu_bo_reserve(bo, true);
+-      amdgpu_bo_kunmap(bo);
+-      amdgpu_bo_unpin(bo);
+-      amdgpu_bo_unreserve(bo);
+-      amdgpu_bo_unref(&(bo));
++      amdgpu_bo_reserve(*bo, true);
++      amdgpu_bo_kunmap(*bo);
++      amdgpu_bo_unpin(*bo);
++      amdgpu_bo_unreserve(*bo);
++      amdgpu_bo_unref(bo);
+ }
+ int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size,
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+index 1de021ebdd467..ee16d8a9ba559 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+@@ -233,7 +233,7 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo,
+ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size,
+                               void **mem_obj, uint64_t *gpu_addr,
+                               void **cpu_ptr, bool mqd_gfx9);
+-void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void *mem_obj);
++void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj);
+ int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size,
+                               void **mem_obj);
+ void amdgpu_amdkfd_free_gws(struct amdgpu_device *adev, void *mem_obj);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+index fdf171ad4a3c6..4f260adce8c46 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+@@ -423,7 +423,7 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
+ err_create_queue:
+       if (wptr_bo)
+-              amdgpu_amdkfd_free_gtt_mem(dev->adev, wptr_bo);
++              amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&wptr_bo);
+ err_wptr_map_gart:
+ err_bind_process:
+ err_pdd:
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+index afc57df421cd9..3343079f28c90 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+@@ -863,7 +863,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
+ kfd_doorbell_error:
+       kfd_gtt_sa_fini(kfd);
+ kfd_gtt_sa_init_error:
+-      amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem);
++      amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem);
+ alloc_gtt_mem_failure:
+       dev_err(kfd_device,
+               "device %x:%x NOT added due to errors\n",
+@@ -881,7 +881,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
+               kfd_doorbell_fini(kfd);
+               ida_destroy(&kfd->doorbell_ida);
+               kfd_gtt_sa_fini(kfd);
+-              amdgpu_amdkfd_free_gtt_mem(kfd->adev, kfd->gtt_mem);
++              amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem);
+       }
+       kfree(kfd);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+index c08b6ee252898..dbef9eac2694f 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+@@ -2633,7 +2633,7 @@ static void deallocate_hiq_sdma_mqd(struct kfd_node *dev,
+ {
+       WARN(!mqd, "No hiq sdma mqd trunk to free");
+-      amdgpu_amdkfd_free_gtt_mem(dev->adev, mqd->gtt_mem);
++      amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem);
+ }
+ void device_queue_manager_uninit(struct device_queue_manager *dqm)
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+index 8746a61a852dc..d501fd2222dc3 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+@@ -223,7 +223,7 @@ void kfd_free_mqd_cp(struct mqd_manager *mm, void *mqd,
+             struct kfd_mem_obj *mqd_mem_obj)
+ {
+       if (mqd_mem_obj->gtt_mem) {
+-              amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, mqd_mem_obj->gtt_mem);
++              amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, &mqd_mem_obj->gtt_mem);
+               kfree(mqd_mem_obj);
+       } else {
+               kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index 451bb058cc620..66150ea8e64d8 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -1048,7 +1048,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
+               if (pdd->dev->kfd->shared_resources.enable_mes)
+                       amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev,
+-                                                 pdd->proc_ctx_bo);
++                                                 &pdd->proc_ctx_bo);
+               /*
+                * before destroying pdd, make sure to report availability
+                * for auto suspend
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+index a5bdc3258ae54..c97b4fc44859d 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+@@ -201,9 +201,9 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm,
+       }
+       if (dev->kfd->shared_resources.enable_mes) {
+-              amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->gang_ctx_bo);
++              amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo);
+               if (pqn->q->wptr_bo)
+-                      amdgpu_amdkfd_free_gtt_mem(dev->adev, pqn->q->wptr_bo);
++                      amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo);
+       }
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch b/queue-6.10/drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch
new file mode 100644 (file)
index 0000000..8185010
--- /dev/null
@@ -0,0 +1,76 @@
+From 67598afe98001e0008aefbc9727d2926b33a7209 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 13:56:32 +0800
+Subject: drm/amdkfd: Check int source id for utcl2 poison event
+
+From: Hawking Zhang <Hawking.Zhang@amd.com>
+
+[ Upstream commit db6341a9168d2a24ded526277eeab29724d76e9d ]
+
+Traditional utcl2 fault_status polling does not
+work in SRIOV environment. The polling of fault
+status register from guest side will be dropped
+by hardware.
+
+Driver should switch to check utcl2 interrupt
+source id to identify utcl2 poison event. It is
+set to 1 when poisoned data interrupts are
+signaled.
+
+v2: drop the unused local variable (Tao)
+
+Signed-off-by: Hawking Zhang <Hawking.Zhang@amd.com>
+Reviewed-by: Tao Zhou <tao.zhou1@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c    | 18 +-----------------
+ drivers/gpu/drm/amd/amdkfd/soc15_int.h         |  1 +
+ 2 files changed, 2 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+index 78dde62fb04ad..c282f5253c445 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+@@ -414,25 +414,9 @@ static void event_interrupt_wq_v9(struct kfd_node *dev,
+                  client_id == SOC15_IH_CLIENTID_UTCL2) {
+               struct kfd_vm_fault_info info = {0};
+               uint16_t ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry);
+-              uint32_t node_id = SOC15_NODEID_FROM_IH_ENTRY(ih_ring_entry);
+-              uint32_t vmid_type = SOC15_VMID_TYPE_FROM_IH_ENTRY(ih_ring_entry);
+-              int hub_inst = 0;
+               struct kfd_hsa_memory_exception_data exception_data;
+-              /* gfxhub */
+-              if (!vmid_type && dev->adev->gfx.funcs->ih_node_to_logical_xcc) {
+-                      hub_inst = dev->adev->gfx.funcs->ih_node_to_logical_xcc(dev->adev,
+-                              node_id);
+-                      if (hub_inst < 0)
+-                              hub_inst = 0;
+-              }
+-
+-              /* mmhub */
+-              if (vmid_type && client_id == SOC15_IH_CLIENTID_VMC)
+-                      hub_inst = node_id / 4;
+-
+-              if (amdgpu_amdkfd_ras_query_utcl2_poison_status(dev->adev,
+-                                      hub_inst, vmid_type)) {
++              if (source_id == SOC15_INTSRC_VMC_UTCL2_POISON) {
+                       event_interrupt_poison_consumption_v9(dev, pasid, client_id);
+                       return;
+               }
+diff --git a/drivers/gpu/drm/amd/amdkfd/soc15_int.h b/drivers/gpu/drm/amd/amdkfd/soc15_int.h
+index 10138676f27fd..e5c0205f26181 100644
+--- a/drivers/gpu/drm/amd/amdkfd/soc15_int.h
++++ b/drivers/gpu/drm/amd/amdkfd/soc15_int.h
+@@ -29,6 +29,7 @@
+ #define SOC15_INTSRC_CP_BAD_OPCODE    183
+ #define SOC15_INTSRC_SQ_INTERRUPT_MSG 239
+ #define SOC15_INTSRC_VMC_FAULT                0
++#define SOC15_INTSRC_VMC_UTCL2_POISON 1
+ #define SOC15_INTSRC_SDMA_TRAP                224
+ #define SOC15_INTSRC_SDMA_ECC         220
+ #define SOC21_INTSRC_SDMA_TRAP                49
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch b/queue-6.10/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch
new file mode 100644 (file)
index 0000000..4488d04
--- /dev/null
@@ -0,0 +1,35 @@
+From 416b2b78a2d2b5ec7daf9c298860cdfd931a5145 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 11:29:55 +0800
+Subject: drm/amdkfd: Fix resource leak in criu restore queue
+
+From: Jesse Zhang <jesse.zhang@amd.com>
+
+[ Upstream commit aa47fe8d3595365a935921a90d00bc33ee374728 ]
+
+To avoid memory leaks, release q_extra_data when exiting the restore queue.
+v2: Correct the proto (Alex)
+
+Signed-off-by: Jesse Zhang <jesse.zhang@amd.com>
+Reviewed-by: Tim Huang <tim.huang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+index c97b4fc44859d..db2b71f7226f4 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+@@ -984,6 +984,7 @@ int kfd_criu_restore_queue(struct kfd_process *p,
+               pr_debug("Queue id %d was restored successfully\n", queue_id);
+       kfree(q_data);
++      kfree(q_extra_data);
+       return ret;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch b/queue-6.10/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch
new file mode 100644 (file)
index 0000000..055f145
--- /dev/null
@@ -0,0 +1,61 @@
+From dbfe4ad3ff1f05785d9f5662d3dc94c6ae7d14fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Jul 2024 13:15:40 +0200
+Subject: drm/msm/adreno: Assign msm_gpu->pdev earlier to avoid nullptrs
+
+From: Konrad Dybcio <konrad.dybcio@linaro.org>
+
+[ Upstream commit 16007768551d5bfe53426645401435ca8d2ef54f ]
+
+There are some cases, such as the one uncovered by Commit 46d4efcccc68
+("drm/msm/a6xx: Avoid a nullptr dereference when speedbin setting fails")
+where
+
+msm_gpu_cleanup() : platform_set_drvdata(gpu->pdev, NULL);
+
+is called on gpu->pdev == NULL, as the GPU device has not been fully
+initialized yet.
+
+Turns out that there's more than just the aforementioned path that
+causes this to happen (e.g. the case when there's speedbin data in the
+catalog, but opp-supported-hw is missing in DT).
+
+Assigning msm_gpu->pdev earlier seems like the least painful solution
+to this, therefore do so.
+
+Signed-off-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Patchwork: https://patchwork.freedesktop.org/patch/602742/
+Signed-off-by: Rob Clark <robdclark@chromium.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 1 +
+ drivers/gpu/drm/msm/msm_gpu.c           | 1 -
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+index d5d9361e11aa5..8e8f55225e1ea 100644
+--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+@@ -1079,6 +1079,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
+       adreno_gpu->chip_id = config->chip_id;
+       gpu->allow_relocs = config->info->family < ADRENO_6XX_GEN1;
++      gpu->pdev = pdev;
+       /* Only handle the core clock when GMU is not in use (or is absent). */
+       if (adreno_has_gmu_wrapper(adreno_gpu) ||
+diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
+index cd185b9636d26..56b6de049bd7b 100644
+--- a/drivers/gpu/drm/msm/msm_gpu.c
++++ b/drivers/gpu/drm/msm/msm_gpu.c
+@@ -929,7 +929,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
+       if (IS_ERR(gpu->gpu_cx))
+               gpu->gpu_cx = NULL;
+-      gpu->pdev = pdev;
+       platform_set_drvdata(pdev, &gpu->adreno_smmu);
+       msm_devfreq_init(gpu);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-printer-allow-null-data-in-devcoredump-printer.patch b/queue-6.10/drm-printer-allow-null-data-in-devcoredump-printer.patch
new file mode 100644 (file)
index 0000000..c9ae3ef
--- /dev/null
@@ -0,0 +1,144 @@
+From 168e280227eb6a7ce3b4c50d2b0efc343091f448 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 08:41:17 -0700
+Subject: drm/printer: Allow NULL data in devcoredump printer
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit 53369581dc0c68a5700ed51e1660f44c4b2bb524 ]
+
+We want to determine the size of the devcoredump before writing it out.
+To that end, we will run the devcoredump printer with NULL data to get
+the size, alloc data based on the generated offset, then run the
+devcorecump again with a valid data pointer to print.  This necessitates
+not writing data to the data pointer on the initial pass, when it is
+NULL.
+
+v5:
+ - Better commit message (Jonathan)
+ - Add kerenl doc with examples (Jani)
+
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240801154118.2547543-3-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/drm_print.c | 13 +++++----
+ include/drm/drm_print.h     | 54 ++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 61 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
+index cf2efb44722c9..1d122d4de70ec 100644
+--- a/drivers/gpu/drm/drm_print.c
++++ b/drivers/gpu/drm/drm_print.c
+@@ -100,8 +100,9 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str)
+                       copy = iterator->remain;
+               /* Copy out the bit of the string that we need */
+-              memcpy(iterator->data,
+-                      str + (iterator->start - iterator->offset), copy);
++              if (iterator->data)
++                      memcpy(iterator->data,
++                             str + (iterator->start - iterator->offset), copy);
+               iterator->offset = iterator->start + copy;
+               iterator->remain -= copy;
+@@ -110,7 +111,8 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str)
+               len = min_t(ssize_t, strlen(str), iterator->remain);
+-              memcpy(iterator->data + pos, str, len);
++              if (iterator->data)
++                      memcpy(iterator->data + pos, str, len);
+               iterator->offset += len;
+               iterator->remain -= len;
+@@ -140,8 +142,9 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf)
+       if ((iterator->offset >= iterator->start) && (len < iterator->remain)) {
+               ssize_t pos = iterator->offset - iterator->start;
+-              snprintf(((char *) iterator->data) + pos,
+-                      iterator->remain, "%pV", vaf);
++              if (iterator->data)
++                      snprintf(((char *) iterator->data) + pos,
++                               iterator->remain, "%pV", vaf);
+               iterator->offset += len;
+               iterator->remain -= len;
+diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h
+index 089950ad8681a..8fad7d09bedae 100644
+--- a/include/drm/drm_print.h
++++ b/include/drm/drm_print.h
+@@ -220,7 +220,8 @@ drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va)
+ /**
+  * struct drm_print_iterator - local struct used with drm_printer_coredump
+- * @data: Pointer to the devcoredump output buffer
++ * @data: Pointer to the devcoredump output buffer, can be NULL if using
++ * drm_printer_coredump to determine size of devcoredump
+  * @start: The offset within the buffer to start writing
+  * @remain: The number of bytes to write for this iteration
+  */
+@@ -265,6 +266,57 @@ struct drm_print_iterator {
+  *                    coredump_read, ...)
+  *    }
+  *
++ * The above example has a time complexity of O(N^2), where N is the size of the
++ * devcoredump. This is acceptable for small devcoredumps but scales poorly for
++ * larger ones.
++ *
++ * Another use case for drm_coredump_printer is to capture the devcoredump into
++ * a saved buffer before the dev_coredump() callback. This involves two passes:
++ * one to determine the size of the devcoredump and another to print it to a
++ * buffer. Then, in dev_coredump(), copy from the saved buffer into the
++ * devcoredump read buffer.
++ *
++ * For example::
++ *
++ *    char *devcoredump_saved_buffer;
++ *
++ *    ssize_t __coredump_print(char *buffer, ssize_t count, ...)
++ *    {
++ *            struct drm_print_iterator iter;
++ *            struct drm_printer p;
++ *
++ *            iter.data = buffer;
++ *            iter.start = 0;
++ *            iter.remain = count;
++ *
++ *            p = drm_coredump_printer(&iter);
++ *
++ *            drm_printf(p, "foo=%d\n", foo);
++ *            ...
++ *            return count - iter.remain;
++ *    }
++ *
++ *    void coredump_print(...)
++ *    {
++ *            ssize_t count;
++ *
++ *            count = __coredump_print(NULL, INT_MAX, ...);
++ *            devcoredump_saved_buffer = kvmalloc(count, GFP_KERNEL);
++ *            __coredump_print(devcoredump_saved_buffer, count, ...);
++ *    }
++ *
++ *    void coredump_read(char *buffer, loff_t offset, size_t count,
++ *                       void *data, size_t datalen)
++ *    {
++ *            ...
++ *            memcpy(buffer, devcoredump_saved_buffer + offset, count);
++ *            ...
++ *    }
++ *
++ * The above example has a time complexity of O(N*2), where N is the size of the
++ * devcoredump. This scales better than the previous example for larger
++ * devcoredumps.
++ *
+  * RETURNS:
+  * The &drm_printer object
+  */
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch b/queue-6.10/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch
new file mode 100644 (file)
index 0000000..8f7b950
--- /dev/null
@@ -0,0 +1,140 @@
+From 638094311e34f49390d48489255ba890335e4fad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 30 Jul 2024 17:58:12 +0200
+Subject: drm/radeon/r100: Handle unknown family in r100_cp_init_microcode()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit c6dbab46324b1742b50dc2fb5c1fee2c28129439 ]
+
+With -Werror:
+
+    In function ‘r100_cp_init_microcode’,
+       inlined from ‘r100_cp_init’ at drivers/gpu/drm/radeon/r100.c:1136:7:
+    include/linux/printk.h:465:44: error: ‘%s’ directive argument is null [-Werror=format-overflow=]
+      465 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
+         |                                            ^
+    include/linux/printk.h:437:17: note: in definition of macro ‘printk_index_wrap’
+      437 |                 _p_func(_fmt, ##__VA_ARGS__);                           \
+         |                 ^~~~~~~
+    include/linux/printk.h:508:9: note: in expansion of macro ‘printk’
+      508 |         printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+         |         ^~~~~~
+    drivers/gpu/drm/radeon/r100.c:1062:17: note: in expansion of macro ‘pr_err’
+     1062 |                 pr_err("radeon_cp: Failed to load firmware \"%s\"\n", fw_name);
+         |                 ^~~~~~
+
+Fix this by converting the if/else if/... construct into a proper
+switch() statement with a default to handle the error case.
+
+As a bonus, the generated code is ca. 100 bytes smaller (with gcc 11.4.0
+targeting arm32).
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/radeon/r100.c | 70 ++++++++++++++++++++++-------------
+ 1 file changed, 45 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
+index 0b1e19345f43a..bfd42e3e161e9 100644
+--- a/drivers/gpu/drm/radeon/r100.c
++++ b/drivers/gpu/drm/radeon/r100.c
+@@ -1016,45 +1016,65 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)
+       DRM_DEBUG_KMS("\n");
+-      if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) ||
+-          (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) ||
+-          (rdev->family == CHIP_RS200)) {
++      switch (rdev->family) {
++      case CHIP_R100:
++      case CHIP_RV100:
++      case CHIP_RV200:
++      case CHIP_RS100:
++      case CHIP_RS200:
+               DRM_INFO("Loading R100 Microcode\n");
+               fw_name = FIRMWARE_R100;
+-      } else if ((rdev->family == CHIP_R200) ||
+-                 (rdev->family == CHIP_RV250) ||
+-                 (rdev->family == CHIP_RV280) ||
+-                 (rdev->family == CHIP_RS300)) {
++              break;
++
++      case CHIP_R200:
++      case CHIP_RV250:
++      case CHIP_RV280:
++      case CHIP_RS300:
+               DRM_INFO("Loading R200 Microcode\n");
+               fw_name = FIRMWARE_R200;
+-      } else if ((rdev->family == CHIP_R300) ||
+-                 (rdev->family == CHIP_R350) ||
+-                 (rdev->family == CHIP_RV350) ||
+-                 (rdev->family == CHIP_RV380) ||
+-                 (rdev->family == CHIP_RS400) ||
+-                 (rdev->family == CHIP_RS480)) {
++              break;
++
++      case CHIP_R300:
++      case CHIP_R350:
++      case CHIP_RV350:
++      case CHIP_RV380:
++      case CHIP_RS400:
++      case CHIP_RS480:
+               DRM_INFO("Loading R300 Microcode\n");
+               fw_name = FIRMWARE_R300;
+-      } else if ((rdev->family == CHIP_R420) ||
+-                 (rdev->family == CHIP_R423) ||
+-                 (rdev->family == CHIP_RV410)) {
++              break;
++
++      case CHIP_R420:
++      case CHIP_R423:
++      case CHIP_RV410:
+               DRM_INFO("Loading R400 Microcode\n");
+               fw_name = FIRMWARE_R420;
+-      } else if ((rdev->family == CHIP_RS690) ||
+-                 (rdev->family == CHIP_RS740)) {
++              break;
++
++      case CHIP_RS690:
++      case CHIP_RS740:
+               DRM_INFO("Loading RS690/RS740 Microcode\n");
+               fw_name = FIRMWARE_RS690;
+-      } else if (rdev->family == CHIP_RS600) {
++              break;
++
++      case CHIP_RS600:
+               DRM_INFO("Loading RS600 Microcode\n");
+               fw_name = FIRMWARE_RS600;
+-      } else if ((rdev->family == CHIP_RV515) ||
+-                 (rdev->family == CHIP_R520) ||
+-                 (rdev->family == CHIP_RV530) ||
+-                 (rdev->family == CHIP_R580) ||
+-                 (rdev->family == CHIP_RV560) ||
+-                 (rdev->family == CHIP_RV570)) {
++              break;
++
++      case CHIP_RV515:
++      case CHIP_R520:
++      case CHIP_RV530:
++      case CHIP_R580:
++      case CHIP_RV560:
++      case CHIP_RV570:
+               DRM_INFO("Loading R500 Microcode\n");
+               fw_name = FIRMWARE_R520;
++              break;
++
++      default:
++              DRM_ERROR("Unsupported Radeon family %u\n", rdev->family);
++              return -EINVAL;
+       }
+       err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch b/queue-6.10/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch
new file mode 100644 (file)
index 0000000..f5d2a0e
--- /dev/null
@@ -0,0 +1,254 @@
+From 42aa6221cd6f0d02ca188473a9238d6854f5b0d7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Feb 2024 15:50:40 +0300
+Subject: drm/stm: Avoid use-after-free issues with crtc and plane
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Katya Orlova <e.orlova@ispras.ru>
+
+[ Upstream commit 19dd9780b7ac673be95bf6fd6892a184c9db611f ]
+
+ltdc_load() calls functions drm_crtc_init_with_planes(),
+drm_universal_plane_init() and drm_encoder_init(). These functions
+should not be called with parameters allocated with devm_kzalloc()
+to avoid use-after-free issues [1].
+
+Use allocations managed by the DRM framework.
+
+Found by Linux Verification Center (linuxtesting.org).
+
+[1]
+https://lore.kernel.org/lkml/u366i76e3qhh3ra5oxrtngjtm2u5lterkekcz6y2jkndhuxzli@diujon4h7qwb/
+
+Signed-off-by: Katya Orlova <e.orlova@ispras.ru>
+Acked-by: Raphaël Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240216125040.8968-1-e.orlova@ispras.ru
+Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/stm/drv.c  |  3 +-
+ drivers/gpu/drm/stm/ltdc.c | 73 ++++++++++----------------------------
+ 2 files changed, 20 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
+index 4d2db079ad4ff..e1232f74dfa53 100644
+--- a/drivers/gpu/drm/stm/drv.c
++++ b/drivers/gpu/drm/stm/drv.c
+@@ -25,6 +25,7 @@
+ #include <drm/drm_module.h>
+ #include <drm/drm_probe_helper.h>
+ #include <drm/drm_vblank.h>
++#include <drm/drm_managed.h>
+ #include "ltdc.h"
+@@ -75,7 +76,7 @@ static int drv_load(struct drm_device *ddev)
+       DRM_DEBUG("%s\n", __func__);
+-      ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL);
++      ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL);
+       if (!ldev)
+               return -ENOMEM;
+diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
+index 5aec1e58c968c..056642d12265c 100644
+--- a/drivers/gpu/drm/stm/ltdc.c
++++ b/drivers/gpu/drm/stm/ltdc.c
+@@ -36,6 +36,7 @@
+ #include <drm/drm_probe_helper.h>
+ #include <drm/drm_simple_kms_helper.h>
+ #include <drm/drm_vblank.h>
++#include <drm/drm_managed.h>
+ #include <video/videomode.h>
+@@ -1199,7 +1200,6 @@ static void ltdc_crtc_atomic_print_state(struct drm_printer *p,
+ }
+ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
+-      .destroy = drm_crtc_cleanup,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .reset = drm_atomic_helper_crtc_reset,
+@@ -1212,7 +1212,6 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
+ };
+ static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = {
+-      .destroy = drm_crtc_cleanup,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .reset = drm_atomic_helper_crtc_reset,
+@@ -1545,7 +1544,6 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p,
+ static const struct drm_plane_funcs ltdc_plane_funcs = {
+       .update_plane = drm_atomic_helper_update_plane,
+       .disable_plane = drm_atomic_helper_disable_plane,
+-      .destroy = drm_plane_cleanup,
+       .reset = drm_atomic_helper_plane_reset,
+       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+@@ -1572,7 +1570,6 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
+       const u64 *modifiers = ltdc_format_modifiers;
+       u32 lofs = index * LAY_OFS;
+       u32 val;
+-      int ret;
+       /* Allocate the biggest size according to supported color formats */
+       formats = devm_kzalloc(dev, (ldev->caps.pix_fmt_nb +
+@@ -1615,14 +1612,10 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
+               }
+       }
+-      plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
+-      if (!plane)
+-              return NULL;
+-
+-      ret = drm_universal_plane_init(ddev, plane, possible_crtcs,
+-                                     &ltdc_plane_funcs, formats, nb_fmt,
+-                                     modifiers, type, NULL);
+-      if (ret < 0)
++      plane = drmm_universal_plane_alloc(ddev, struct drm_plane, dev,
++                                         possible_crtcs, &ltdc_plane_funcs, formats,
++                                         nb_fmt, modifiers, type, NULL);
++      if (IS_ERR(plane))
+               return NULL;
+       if (ldev->caps.ycbcr_input) {
+@@ -1645,15 +1638,6 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
+       return plane;
+ }
+-static void ltdc_plane_destroy_all(struct drm_device *ddev)
+-{
+-      struct drm_plane *plane, *plane_temp;
+-
+-      list_for_each_entry_safe(plane, plane_temp,
+-                               &ddev->mode_config.plane_list, head)
+-              drm_plane_cleanup(plane);
+-}
+-
+ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+ {
+       struct ltdc_device *ldev = ddev->dev_private;
+@@ -1679,14 +1663,14 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+       /* Init CRTC according to its hardware features */
+       if (ldev->caps.crc)
+-              ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
+-                                              &ltdc_crtc_with_crc_support_funcs, NULL);
++              ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL,
++                                               &ltdc_crtc_with_crc_support_funcs, NULL);
+       else
+-              ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL,
+-                                              &ltdc_crtc_funcs, NULL);
++              ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL,
++                                               &ltdc_crtc_funcs, NULL);
+       if (ret) {
+               DRM_ERROR("Can not initialize CRTC\n");
+-              goto cleanup;
++              return ret;
+       }
+       drm_crtc_helper_add(crtc, &ltdc_crtc_helper_funcs);
+@@ -1700,9 +1684,8 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+       for (i = 1; i < ldev->caps.nb_layers; i++) {
+               overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i);
+               if (!overlay) {
+-                      ret = -ENOMEM;
+                       DRM_ERROR("Can not create overlay plane %d\n", i);
+-                      goto cleanup;
++                      return -ENOMEM;
+               }
+               if (ldev->caps.dynamic_zorder)
+                       drm_plane_create_zpos_property(overlay, i, 0, ldev->caps.nb_layers - 1);
+@@ -1715,10 +1698,6 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
+       }
+       return 0;
+-
+-cleanup:
+-      ltdc_plane_destroy_all(ddev);
+-      return ret;
+ }
+ static void ltdc_encoder_disable(struct drm_encoder *encoder)
+@@ -1778,23 +1757,19 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
+       struct drm_encoder *encoder;
+       int ret;
+-      encoder = devm_kzalloc(ddev->dev, sizeof(*encoder), GFP_KERNEL);
+-      if (!encoder)
+-              return -ENOMEM;
++      encoder = drmm_simple_encoder_alloc(ddev, struct drm_encoder, dev,
++                                          DRM_MODE_ENCODER_DPI);
++      if (IS_ERR(encoder))
++              return PTR_ERR(encoder);
+       encoder->possible_crtcs = CRTC_MASK;
+       encoder->possible_clones = 0;   /* No cloning support */
+-      drm_simple_encoder_init(ddev, encoder, DRM_MODE_ENCODER_DPI);
+-
+       drm_encoder_helper_add(encoder, &ltdc_encoder_helper_funcs);
+       ret = drm_bridge_attach(encoder, bridge, NULL, 0);
+-      if (ret) {
+-              if (ret != -EPROBE_DEFER)
+-                      drm_encoder_cleanup(encoder);
++      if (ret)
+               return ret;
+-      }
+       DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id);
+@@ -1964,8 +1939,7 @@ int ltdc_load(struct drm_device *ddev)
+                       goto err;
+               if (panel) {
+-                      bridge = drm_panel_bridge_add_typed(panel,
+-                                                          DRM_MODE_CONNECTOR_DPI);
++                      bridge = drmm_panel_bridge_add(ddev, panel);
+                       if (IS_ERR(bridge)) {
+                               DRM_ERROR("panel-bridge endpoint %d\n", i);
+                               ret = PTR_ERR(bridge);
+@@ -2047,7 +2021,7 @@ int ltdc_load(struct drm_device *ddev)
+               }
+       }
+-      crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);
++      crtc = drmm_kzalloc(ddev, sizeof(*crtc), GFP_KERNEL);
+       if (!crtc) {
+               DRM_ERROR("Failed to allocate crtc\n");
+               ret = -ENOMEM;
+@@ -2074,9 +2048,6 @@ int ltdc_load(struct drm_device *ddev)
+       return 0;
+ err:
+-      for (i = 0; i < nb_endpoints; i++)
+-              drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
+-
+       clk_disable_unprepare(ldev->pixel_clk);
+       return ret;
+@@ -2084,16 +2055,8 @@ int ltdc_load(struct drm_device *ddev)
+ void ltdc_unload(struct drm_device *ddev)
+ {
+-      struct device *dev = ddev->dev;
+-      int nb_endpoints, i;
+-
+       DRM_DEBUG_DRIVER("\n");
+-      nb_endpoints = of_graph_get_endpoint_count(dev->of_node);
+-
+-      for (i = 0; i < nb_endpoints; i++)
+-              drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
+-
+       pm_runtime_disable(ddev->dev);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch b/queue-6.10/drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch
new file mode 100644 (file)
index 0000000..3656c23
--- /dev/null
@@ -0,0 +1,38 @@
+From 17786c82acde9ca57fb5ab0b229c524acf894393 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jul 2024 15:13:44 +0200
+Subject: drm/stm: ltdc: reset plane transparency after plane disable
+
+From: Yannick Fertre <yannick.fertre@foss.st.com>
+
+[ Upstream commit 02fa62d41c8abff945bae5bfc3ddcf4721496aca ]
+
+The plane's opacity should be reseted while the plane
+is disabled. It prevents from seeing a possible global
+or layer background color set earlier.
+
+Signed-off-by: Yannick Fertre <yannick.fertre@foss.st.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240712131344.98113-1-yannick.fertre@foss.st.com
+Signed-off-by: Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/stm/ltdc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
+index 056642d12265c..0832b749b66e7 100644
+--- a/drivers/gpu/drm/stm/ltdc.c
++++ b/drivers/gpu/drm/stm/ltdc.c
+@@ -1513,6 +1513,9 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane,
+       /* Disable layer */
+       regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN | LXCR_CLUTEN |  LXCR_HMEN, 0);
++      /* Reset the layer transparency to hide any related background color */
++      regmap_write_bits(ldev->regmap, LTDC_L1CACR + lofs, LXCACR_CONSTA, 0x00);
++
+       /* Commit shadow registers = update plane at next vblank */
+       if (ldev->caps.plane_reg_shadow)
+               regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs,
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-xe-drop-warn-on-xe_guc_pc_gucrc_disable-in-guc-p.patch b/queue-6.10/drm-xe-drop-warn-on-xe_guc_pc_gucrc_disable-in-guc-p.patch
new file mode 100644 (file)
index 0000000..d91213a
--- /dev/null
@@ -0,0 +1,35 @@
+From ad6e9a25aa93423cebf61c569d849df0fd99ccb9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 10:29:55 -0700
+Subject: drm/xe: Drop warn on xe_guc_pc_gucrc_disable in guc pc fini
+
+From: Matthew Brost <matthew.brost@intel.com>
+
+[ Upstream commit a323782567812ee925e9b7926445532c7afe331b ]
+
+Not a big deal if CT is down as driver is unloading, no need to warn.
+
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Reviewed-by: Jagmeet Randhawa <jagmeet.randhawa@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240820172958.1095143-4-matthew.brost@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_guc_pc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c
+index 23382ced4ea74..69f8b6fdaeaea 100644
+--- a/drivers/gpu/drm/xe/xe_guc_pc.c
++++ b/drivers/gpu/drm/xe/xe_guc_pc.c
+@@ -897,7 +897,7 @@ static void xe_guc_pc_fini(struct drm_device *drm, void *arg)
+       struct xe_guc_pc *pc = arg;
+       XE_WARN_ON(xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL));
+-      XE_WARN_ON(xe_guc_pc_gucrc_disable(pc));
++      xe_guc_pc_gucrc_disable(pc);
+       XE_WARN_ON(xe_guc_pc_stop(pc));
+       xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-xe-hdcp-check-gsc-structure-validity.patch b/queue-6.10/drm-xe-hdcp-check-gsc-structure-validity.patch
new file mode 100644 (file)
index 0000000..b5e5114
--- /dev/null
@@ -0,0 +1,52 @@
+From b6aed06ec0735572dd40b9228925c51607bc08cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 12:14:51 +0530
+Subject: drm/xe/hdcp: Check GSC structure validity
+
+From: Suraj Kandpal <suraj.kandpal@intel.com>
+
+[ Upstream commit b4224f6bae3801d589f815672ec62800a1501b0d ]
+
+Sometimes xe_gsc is not initialized when checked at HDCP capability
+check. Add gsc structure check to avoid null pointer error.
+
+Signed-off-by: Suraj Kandpal <suraj.kandpal@intel.com>
+Reviewed-by: Dnyaneshwar Bhadane <dnyaneshwar.bhadane@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240722064451.3610512-4-suraj.kandpal@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/display/xe_hdcp_gsc.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+index b3d3c065dd9d8..2f935771658e6 100644
+--- a/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
++++ b/drivers/gpu/drm/xe/display/xe_hdcp_gsc.c
+@@ -39,10 +39,14 @@ bool intel_hdcp_gsc_check_status(struct xe_device *xe)
+ {
+       struct xe_tile *tile = xe_device_get_root_tile(xe);
+       struct xe_gt *gt = tile->media_gt;
++      struct xe_gsc *gsc = &gt->uc.gsc;
+       bool ret = true;
+-      if (!xe_uc_fw_is_enabled(&gt->uc.gsc.fw))
++      if (!gsc && !xe_uc_fw_is_enabled(&gsc->fw)) {
++              drm_dbg_kms(&xe->drm,
++                          "GSC Components not ready for HDCP2.x\n");
+               return false;
++      }
+       xe_pm_runtime_get(xe);
+       if (xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC)) {
+@@ -52,7 +56,7 @@ bool intel_hdcp_gsc_check_status(struct xe_device *xe)
+               goto out;
+       }
+-      if (!xe_gsc_proxy_init_done(&gt->uc.gsc))
++      if (!xe_gsc_proxy_init_done(gsc))
+               ret = false;
+       xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC);
+-- 
+2.43.0
+
diff --git a/queue-6.10/drm-xe-use-topology-to-determine-page-fault-queue-si.patch b/queue-6.10/drm-xe-use-topology-to-determine-page-fault-queue-si.patch
new file mode 100644 (file)
index 0000000..0da0e5d
--- /dev/null
@@ -0,0 +1,165 @@
+From 44b6d959fa09eac2cad49b6fb151a2be866b59d1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Aug 2024 02:47:31 +0000
+Subject: drm/xe: Use topology to determine page fault queue size
+
+From: Stuart Summers <stuart.summers@intel.com>
+
+[ Upstream commit 3338e4f90c143cf32f77d64f464cb7f2c2d24700 ]
+
+Currently the page fault queue size is hard coded. However
+the hardware supports faulting for each EU and each CS.
+For some applications running on hardware with a large
+number of EUs and CSs, this can result in an overflow of
+the page fault queue.
+
+Add a small calculation to determine the page fault queue
+size based on the number of EUs and CSs in the platform as
+detmined by fuses.
+
+Signed-off-by: Stuart Summers <stuart.summers@intel.com>
+Reviewed-by: Matthew Brost <matthew.brost@intel.com>
+Signed-off-by: Matthew Brost <matthew.brost@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/24d582a3b48c97793b8b6a402f34b4b469471636.1723862633.git.stuart.summers@intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt_pagefault.c | 54 +++++++++++++++++++++-------
+ drivers/gpu/drm/xe/xe_gt_types.h     |  9 +++--
+ 2 files changed, 49 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c
+index 67e8efcaa93f1..ee78b4e47dfcb 100644
+--- a/drivers/gpu/drm/xe/xe_gt_pagefault.c
++++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c
+@@ -307,7 +307,7 @@ static bool get_pagefault(struct pf_queue *pf_queue, struct pagefault *pf)
+                       PFD_VIRTUAL_ADDR_LO_SHIFT;
+               pf_queue->tail = (pf_queue->tail + PF_MSG_LEN_DW) %
+-                      PF_QUEUE_NUM_DW;
++                      pf_queue->num_dw;
+               ret = true;
+       }
+       spin_unlock_irq(&pf_queue->lock);
+@@ -319,7 +319,8 @@ static bool pf_queue_full(struct pf_queue *pf_queue)
+ {
+       lockdep_assert_held(&pf_queue->lock);
+-      return CIRC_SPACE(pf_queue->head, pf_queue->tail, PF_QUEUE_NUM_DW) <=
++      return CIRC_SPACE(pf_queue->head, pf_queue->tail,
++                        pf_queue->num_dw) <=
+               PF_MSG_LEN_DW;
+ }
+@@ -332,22 +333,23 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len)
+       u32 asid;
+       bool full;
+-      /*
+-       * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
+-       */
+-      BUILD_BUG_ON(PF_QUEUE_NUM_DW % PF_MSG_LEN_DW);
+-
+       if (unlikely(len != PF_MSG_LEN_DW))
+               return -EPROTO;
+       asid = FIELD_GET(PFD_ASID, msg[1]);
+       pf_queue = gt->usm.pf_queue + (asid % NUM_PF_QUEUE);
++      /*
++       * The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
++       */
++      xe_gt_assert(gt, !(pf_queue->num_dw % PF_MSG_LEN_DW));
++
+       spin_lock_irqsave(&pf_queue->lock, flags);
+       full = pf_queue_full(pf_queue);
+       if (!full) {
+               memcpy(pf_queue->data + pf_queue->head, msg, len * sizeof(u32));
+-              pf_queue->head = (pf_queue->head + len) % PF_QUEUE_NUM_DW;
++              pf_queue->head = (pf_queue->head + len) %
++                      pf_queue->num_dw;
+               queue_work(gt->usm.pf_wq, &pf_queue->worker);
+       } else {
+               drm_warn(&xe->drm, "PF Queue full, shouldn't be possible");
+@@ -406,26 +408,54 @@ static void pagefault_fini(void *arg)
+ {
+       struct xe_gt *gt = arg;
+       struct xe_device *xe = gt_to_xe(gt);
++      int i;
+       if (!xe->info.has_usm)
+               return;
+       destroy_workqueue(gt->usm.acc_wq);
+       destroy_workqueue(gt->usm.pf_wq);
++
++      for (i = 0; i < NUM_PF_QUEUE; ++i)
++              kfree(gt->usm.pf_queue[i].data);
++}
++
++static int xe_alloc_pf_queue(struct xe_gt *gt, struct pf_queue *pf_queue)
++{
++      xe_dss_mask_t all_dss;
++      int num_dss, num_eus;
++
++      bitmap_or(all_dss, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask,
++                XE_MAX_DSS_FUSE_BITS);
++
++      num_dss = bitmap_weight(all_dss, XE_MAX_DSS_FUSE_BITS);
++      num_eus = bitmap_weight(gt->fuse_topo.eu_mask_per_dss,
++                              XE_MAX_EU_FUSE_BITS) * num_dss;
++
++      /* user can issue separate page faults per EU and per CS */
++      pf_queue->num_dw =
++              (num_eus + XE_NUM_HW_ENGINES) * PF_MSG_LEN_DW;
++
++      pf_queue->gt = gt;
++      pf_queue->data = kzalloc(pf_queue->num_dw, GFP_KERNEL);
++      spin_lock_init(&pf_queue->lock);
++      INIT_WORK(&pf_queue->worker, pf_queue_work_func);
++
++      return 0;
+ }
+ int xe_gt_pagefault_init(struct xe_gt *gt)
+ {
+       struct xe_device *xe = gt_to_xe(gt);
+-      int i;
++      int i, ret = 0;
+       if (!xe->info.has_usm)
+               return 0;
+       for (i = 0; i < NUM_PF_QUEUE; ++i) {
+-              gt->usm.pf_queue[i].gt = gt;
+-              spin_lock_init(&gt->usm.pf_queue[i].lock);
+-              INIT_WORK(&gt->usm.pf_queue[i].worker, pf_queue_work_func);
++              ret = xe_alloc_pf_queue(gt, &gt->usm.pf_queue[i]);
++              if (ret)
++                      return ret;
+       }
+       for (i = 0; i < NUM_ACC_QUEUE; ++i) {
+               gt->usm.acc_queue[i].gt = gt;
+diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
+index cfdc761ff7f46..2dbea50cd8f98 100644
+--- a/drivers/gpu/drm/xe/xe_gt_types.h
++++ b/drivers/gpu/drm/xe/xe_gt_types.h
+@@ -229,9 +229,14 @@ struct xe_gt {
+               struct pf_queue {
+                       /** @usm.pf_queue.gt: back pointer to GT */
+                       struct xe_gt *gt;
+-#define PF_QUEUE_NUM_DW       128
+                       /** @usm.pf_queue.data: data in the page fault queue */
+-                      u32 data[PF_QUEUE_NUM_DW];
++                      u32 *data;
++                      /**
++                       * @usm.pf_queue.num_dw: number of DWORDS in the page
++                       * fault queue. Dynamically calculated based on the number
++                       * of compute resources available.
++                       */
++                      u32 num_dw;
+                       /**
+                        * @usm.pf_queue.tail: tail pointer in DWs for page fault queue,
+                        * moved by worker which processes faults (consumer).
+-- 
+2.43.0
+
diff --git a/queue-6.10/e1000e-avoid-failing-the-system-during-pm_suspend.patch b/queue-6.10/e1000e-avoid-failing-the-system-during-pm_suspend.patch
new file mode 100644 (file)
index 0000000..b5e5fb9
--- /dev/null
@@ -0,0 +1,104 @@
+From 6bd74c3a8b3e468d6c892b613191222ba19ac1a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 16:23:48 +0300
+Subject: e1000e: avoid failing the system during pm_suspend
+
+From: Vitaly Lifshits <vitaly.lifshits@intel.com>
+
+[ Upstream commit 0a6ad4d9e1690c7faa3a53f762c877e477093657 ]
+
+Occasionally when the system goes into pm_suspend, the suspend might fail
+due to a PHY access error on the network adapter. Previously, this would
+have caused the whole system to fail to go to a low power state.
+An example of this was reported in the following Bugzilla:
+https://bugzilla.kernel.org/show_bug.cgi?id=205015
+
+[ 1663.694828] e1000e 0000:00:19.0 eth0: Failed to disable ULP
+[ 1664.731040] asix 2-3:1.0 eth1: link up, 100Mbps, full-duplex, lpa 0xC1E1
+[ 1665.093513] e1000e 0000:00:19.0 eth0: Hardware Error
+[ 1665.596760] e1000e 0000:00:19.0: pci_pm_resume+0x0/0x80 returned 0 after 2975399 usecs
+
+and then the system never recovers from it, and all the following suspend failed due to this
+[22909.393854] PM: pci_pm_suspend(): e1000e_pm_suspend+0x0/0x760 [e1000e] returns -2
+[22909.393858] PM: dpm_run_callback(): pci_pm_suspend+0x0/0x160 returns -2
+[22909.393861] PM: Device 0000:00:1f.6 failed to suspend async: error -2
+
+This can be avoided by changing the return values of __e1000_shutdown and
+e1000e_pm_suspend functions so that they always return 0 (success). This
+is consistent with what other drivers do.
+
+If the e1000e driver encounters a hardware error during suspend, potential
+side effects include slightly higher power draw or non-working wake on
+LAN. This is preferred to a system-level suspend failure, and a warning
+message is written to the system log, so that the user can be aware that
+the LAN controller experienced a problem during suspend.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=205015
+Suggested-by: Dima Ruinskiy <dima.ruinskiy@intel.com>
+Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
+Tested-by: Mor Bar-Gabay <morx.bar.gabay@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/e1000e/netdev.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
+index 3cd161c6672be..e23eedc791d66 100644
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -6671,8 +6671,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+               if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) {
+                       /* enable wakeup by the PHY */
+                       retval = e1000_init_phy_wakeup(adapter, wufc);
+-                      if (retval)
+-                              return retval;
++                      if (retval) {
++                              e_err("Failed to enable wakeup\n");
++                              goto skip_phy_configurations;
++                      }
+               } else {
+                       /* enable wakeup by the MAC */
+                       ew32(WUFC, wufc);
+@@ -6693,8 +6695,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+                        * or broadcast.
+                        */
+                       retval = e1000_enable_ulp_lpt_lp(hw, !runtime);
+-                      if (retval)
+-                              return retval;
++                      if (retval) {
++                              e_err("Failed to enable ULP\n");
++                              goto skip_phy_configurations;
++                      }
+               }
+       }
+@@ -6726,6 +6730,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+               hw->phy.ops.release(hw);
+       }
++skip_phy_configurations:
+       /* Release control of h/w to f/w.  If f/w is AMT enabled, this
+        * would have already happened in close and is redundant.
+        */
+@@ -6968,15 +6973,13 @@ static int e1000e_pm_suspend(struct device *dev)
+       e1000e_pm_freeze(dev);
+       rc = __e1000_shutdown(pdev, false);
+-      if (rc) {
+-              e1000e_pm_thaw(dev);
+-      } else {
++      if (!rc) {
+               /* Introduce S0ix implementation */
+               if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
+                       e1000e_s0ix_entry_flow(adapter);
+       }
+-      return rc;
++      return 0;
+ }
+ static int e1000e_pm_resume(struct device *dev)
+-- 
+2.43.0
+
diff --git a/queue-6.10/ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch b/queue-6.10/ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch
new file mode 100644 (file)
index 0000000..9921da4
--- /dev/null
@@ -0,0 +1,94 @@
+From 075a93f14384b131bb526b1d28f986563d0e880a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 10:35:24 +0800
+Subject: ext4: avoid use-after-free in ext4_ext_show_leaf()
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit 4e2524ba2ca5f54bdbb9e5153bea00421ef653f5 ]
+
+In ext4_find_extent(), path may be freed by error or be reallocated, so
+using a previously saved *ppath may have been freed and thus may trigger
+use-after-free, as follows:
+
+ext4_split_extent
+  path = *ppath;
+  ext4_split_extent_at(ppath)
+  path = ext4_find_extent(ppath)
+  ext4_split_extent_at(ppath)
+    // ext4_find_extent fails to free path
+    // but zeroout succeeds
+  ext4_ext_show_leaf(inode, path)
+    eh = path[depth].p_hdr
+    // path use-after-free !!!
+
+Similar to ext4_split_extent_at(), we use *ppath directly as an input to
+ext4_ext_show_leaf(). Fix a spelling error by the way.
+
+Same problem in ext4_ext_handle_unwritten_extents(). Since 'path' is only
+used in ext4_ext_show_leaf(), remove 'path' and use *ppath directly.
+
+This issue is triggered only when EXT_DEBUG is defined and therefore does
+not affect functionality.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
+Link: https://patch.msgid.link/20240822023545.1994557-5-libaokun@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/extents.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index e067f2dd0335c..7954430f886d8 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -3287,7 +3287,7 @@ static int ext4_split_extent_at(handle_t *handle,
+ }
+ /*
+- * ext4_split_extents() splits an extent and mark extent which is covered
++ * ext4_split_extent() splits an extent and mark extent which is covered
+  * by @map as split_flags indicates
+  *
+  * It may result in splitting the extent into multiple extents (up to three)
+@@ -3363,7 +3363,7 @@ static int ext4_split_extent(handle_t *handle,
+                       goto out;
+       }
+-      ext4_ext_show_leaf(inode, path);
++      ext4_ext_show_leaf(inode, *ppath);
+ out:
+       return err ? err : allocated;
+ }
+@@ -3828,14 +3828,13 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
+                       struct ext4_ext_path **ppath, int flags,
+                       unsigned int allocated, ext4_fsblk_t newblock)
+ {
+-      struct ext4_ext_path __maybe_unused *path = *ppath;
+       int ret = 0;
+       int err = 0;
+       ext_debug(inode, "logical block %llu, max_blocks %u, flags 0x%x, allocated %u\n",
+                 (unsigned long long)map->m_lblk, map->m_len, flags,
+                 allocated);
+-      ext4_ext_show_leaf(inode, path);
++      ext4_ext_show_leaf(inode, *ppath);
+       /*
+        * When writing into unwritten space, we should not fail to
+@@ -3932,7 +3931,7 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
+       if (allocated > map->m_len)
+               allocated = map->m_len;
+       map->m_len = allocated;
+-      ext4_ext_show_leaf(inode, path);
++      ext4_ext_show_leaf(inode, *ppath);
+ out2:
+       return err ? err : allocated;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch b/queue-6.10/ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch
new file mode 100644 (file)
index 0000000..4a655fb
--- /dev/null
@@ -0,0 +1,56 @@
+From 4fa00095d061d1115320ef696fdbfae86d5a88f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Aug 2024 22:12:41 +0200
+Subject: ext4: don't set SB_RDONLY after filesystem errors
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit d3476f3dad4ad68ae5f6b008ea6591d1520da5d8 ]
+
+When the filesystem is mounted with errors=remount-ro, we were setting
+SB_RDONLY flag to stop all filesystem modifications. We knew this misses
+proper locking (sb->s_umount) and does not go through proper filesystem
+remount procedure but it has been the way this worked since early ext2
+days and it was good enough for catastrophic situation damage
+mitigation. Recently, syzbot has found a way (see link) to trigger
+warnings in filesystem freezing because the code got confused by
+SB_RDONLY changing under its hands. Since these days we set
+EXT4_FLAGS_SHUTDOWN on the superblock which is enough to stop all
+filesystem modifications, modifying SB_RDONLY shouldn't be needed. So
+stop doing that.
+
+Link: https://lore.kernel.org/all/000000000000b90a8e061e21d12f@google.com
+Reported-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Link: https://patch.msgid.link/20240805201241.27286-1-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index edc692984404d..04b78c479fd7a 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -735,11 +735,12 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
+       ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
+       /*
+-       * Make sure updated value of ->s_mount_flags will be visible before
+-       * ->s_flags update
++       * EXT4_FLAGS_SHUTDOWN was set which stops all filesystem
++       * modifications. We don't set SB_RDONLY because that requires
++       * sb->s_umount semaphore and setting it without proper remount
++       * procedure is confusing code such as freeze_super() leading to
++       * deadlocks and other problems.
+        */
+-      smp_wmb();
+-      sb->s_flags |= SB_RDONLY;
+ }
+ static void update_super_work(struct work_struct *work)
+-- 
+2.43.0
+
diff --git a/queue-6.10/ext4-ext4_search_dir-should-return-a-proper-error.patch b/queue-6.10/ext4-ext4_search_dir-should-return-a-proper-error.patch
new file mode 100644 (file)
index 0000000..ea212e7
--- /dev/null
@@ -0,0 +1,86 @@
+From 7acd96814e7cbdea933e4011cdc3a5cc79cc08c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 12:23:21 -0300
+Subject: ext4: ext4_search_dir should return a proper error
+
+From: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+
+[ Upstream commit cd69f8f9de280e331c9e6ff689ced0a688a9ce8f ]
+
+ext4_search_dir currently returns -1 in case of a failure, while it returns
+0 when the name is not found. In such failure cases, it should return an
+error code instead.
+
+This becomes even more important when ext4_find_inline_entry returns an
+error code as well in the next commit.
+
+-EFSCORRUPTED seems appropriate as such error code as these failures would
+be caused by unexpected record lengths and is in line with other instances
+of ext4_check_dir_entry failures.
+
+In the case of ext4_dx_find_entry, the current use of ERR_BAD_DX_DIR was
+left as is to reduce the risk of regressions.
+
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
+Link: https://patch.msgid.link/20240821152324.3621860-2-cascardo@igalia.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/namei.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
+index 1311ad0464b2a..12af7c7e09c1a 100644
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -1526,7 +1526,7 @@ static bool ext4_match(struct inode *parent,
+ }
+ /*
+- * Returns 0 if not found, -1 on failure, and 1 on success
++ * Returns 0 if not found, -EFSCORRUPTED on failure, and 1 on success
+  */
+ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
+                   struct inode *dir, struct ext4_filename *fname,
+@@ -1547,7 +1547,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
+                        * a full check */
+                       if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf,
+                                                buf_size, offset))
+-                              return -1;
++                              return -EFSCORRUPTED;
+                       *res_dir = de;
+                       return 1;
+               }
+@@ -1555,7 +1555,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
+               de_len = ext4_rec_len_from_disk(de->rec_len,
+                                               dir->i_sb->s_blocksize);
+               if (de_len <= 0)
+-                      return -1;
++                      return -EFSCORRUPTED;
+               offset += de_len;
+               de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
+       }
+@@ -1707,8 +1707,10 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
+                       goto cleanup_and_exit;
+               } else {
+                       brelse(bh);
+-                      if (i < 0)
++                      if (i < 0) {
++                              ret = ERR_PTR(i);
+                               goto cleanup_and_exit;
++                      }
+               }
+       next:
+               if (++block >= nblocks)
+@@ -1802,7 +1804,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
+               if (retval == 1)
+                       goto success;
+               brelse(bh);
+-              if (retval == -1) {
++              if (retval < 0) {
+                       bh = ERR_PTR(ERR_BAD_DX_DIR);
+                       goto errout;
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.10/ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch b/queue-6.10/ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch
new file mode 100644 (file)
index 0000000..201dbec
--- /dev/null
@@ -0,0 +1,55 @@
+From baeb28afb2bcc0f4f022dc99679ff8b461d00a9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 15:22:09 +0000
+Subject: ext4: fix i_data_sem unlock order in ext4_ind_migrate()
+
+From: Artem Sadovnikov <ancowi69@gmail.com>
+
+[ Upstream commit cc749e61c011c255d81b192a822db650c68b313f ]
+
+Fuzzing reports a possible deadlock in jbd2_log_wait_commit.
+
+This issue is triggered when an EXT4_IOC_MIGRATE ioctl is set to require
+synchronous updates because the file descriptor is opened with O_SYNC.
+This can lead to the jbd2_journal_stop() function calling
+jbd2_might_wait_for_commit(), potentially causing a deadlock if the
+EXT4_IOC_MIGRATE call races with a write(2) system call.
+
+This problem only arises when CONFIG_PROVE_LOCKING is enabled. In this
+case, the jbd2_might_wait_for_commit macro locks jbd2_handle in the
+jbd2_journal_stop function while i_data_sem is locked. This triggers
+lockdep because the jbd2_journal_start function might also lock the same
+jbd2_handle simultaneously.
+
+Found by Linux Verification Center (linuxtesting.org) with syzkaller.
+
+Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Co-developed-by: Mikhail Ukhin <mish.uxin2012@yandex.ru>
+Signed-off-by: Mikhail Ukhin <mish.uxin2012@yandex.ru>
+Signed-off-by: Artem Sadovnikov <ancowi69@gmail.com>
+Rule: add
+Link: https://lore.kernel.org/stable/20240404095000.5872-1-mish.uxin2012%40yandex.ru
+Link: https://patch.msgid.link/20240829152210.2754-1-ancowi69@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/migrate.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
+index d98ac2af8199f..a5e1492bbaaa5 100644
+--- a/fs/ext4/migrate.c
++++ b/fs/ext4/migrate.c
+@@ -663,8 +663,8 @@ int ext4_ind_migrate(struct inode *inode)
+       if (unlikely(ret2 && !ret))
+               ret = ret2;
+ errout:
+-      ext4_journal_stop(handle);
+       up_write(&EXT4_I(inode)->i_data_sem);
++      ext4_journal_stop(handle);
+ out_unlock:
+       ext4_writepages_up_write(inode->i_sb, alloc_ctx);
+       return ret;
+-- 
+2.43.0
+
diff --git a/queue-6.10/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch b/queue-6.10/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch
new file mode 100644 (file)
index 0000000..74aae53
--- /dev/null
@@ -0,0 +1,73 @@
+From 869de8716716b84fdc41777009b8cda6617b6e31 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 17:25:13 +0200
+Subject: fbdev: efifb: Register sysfs groups through driver core
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit 95cdd538e0e5677efbdf8aade04ec098ab98f457 ]
+
+The driver core can register and cleanup sysfs groups already.
+Make use of that functionality to simplify the error handling and
+cleanup.
+
+Also avoid a UAF race during unregistering where the sysctl attributes
+were usable after the info struct was freed.
+
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/efifb.c | 11 ++---------
+ 1 file changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
+index 8dd82afb3452b..595b8e27bea66 100644
+--- a/drivers/video/fbdev/efifb.c
++++ b/drivers/video/fbdev/efifb.c
+@@ -561,15 +561,10 @@ static int efifb_probe(struct platform_device *dev)
+               break;
+       }
+-      err = sysfs_create_groups(&dev->dev.kobj, efifb_groups);
+-      if (err) {
+-              pr_err("efifb: cannot add sysfs attrs\n");
+-              goto err_unmap;
+-      }
+       err = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (err < 0) {
+               pr_err("efifb: cannot allocate colormap\n");
+-              goto err_groups;
++              goto err_unmap;
+       }
+       err = devm_aperture_acquire_for_platform_device(dev, par->base, par->size);
+@@ -587,8 +582,6 @@ static int efifb_probe(struct platform_device *dev)
+ err_fb_dealloc_cmap:
+       fb_dealloc_cmap(&info->cmap);
+-err_groups:
+-      sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
+ err_unmap:
+       if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+               iounmap(info->screen_base);
+@@ -608,12 +601,12 @@ static void efifb_remove(struct platform_device *pdev)
+       /* efifb_destroy takes care of info cleanup */
+       unregister_framebuffer(info);
+-      sysfs_remove_groups(&pdev->dev.kobj, efifb_groups);
+ }
+ static struct platform_driver efifb_driver = {
+       .driver = {
+               .name = "efi-framebuffer",
++              .dev_groups = efifb_groups,
+       },
+       .probe = efifb_probe,
+       .remove_new = efifb_remove,
+-- 
+2.43.0
+
diff --git a/queue-6.10/fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch b/queue-6.10/fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch
new file mode 100644 (file)
index 0000000..f359f48
--- /dev/null
@@ -0,0 +1,59 @@
+From fe740ec834a2e786e8ed8d06e137719480949c13 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 22:29:52 +0800
+Subject: fbdev: pxafb: Fix possible use after free in pxafb_task()
+
+From: Kaixin Wang <kxwang23@m.fudan.edu.cn>
+
+[ Upstream commit 4a6921095eb04a900e0000da83d9475eb958e61e ]
+
+In the pxafb_probe function, it calls the pxafb_init_fbinfo function,
+after which &fbi->task is associated with pxafb_task. Moreover,
+within this pxafb_init_fbinfo function, the pxafb_blank function
+within the &pxafb_ops struct is capable of scheduling work.
+
+If we remove the module which will call pxafb_remove to make cleanup,
+it will call unregister_framebuffer function which can call
+do_unregister_framebuffer to free fbi->fb through
+put_fb_info(fb_info), while the work mentioned above will be used.
+The sequence of operations that may lead to a UAF bug is as follows:
+
+CPU0                                                CPU1
+
+                                   | pxafb_task
+pxafb_remove                       |
+unregister_framebuffer(info)       |
+do_unregister_framebuffer(fb_info) |
+put_fb_info(fb_info)               |
+// free fbi->fb                    | set_ctrlr_state(fbi, state)
+                                   | __pxafb_lcd_power(fbi, 0)
+                                   | fbi->lcd_power(on, &fbi->fb.var)
+                                   | //use fbi->fb
+
+Fix it by ensuring that the work is canceled before proceeding
+with the cleanup in pxafb_remove.
+
+Note that only root user can remove the driver at runtime.
+
+Signed-off-by: Kaixin Wang <kxwang23@m.fudan.edu.cn>
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/fbdev/pxafb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c
+index 2ef56fa28aff3..5ce02495cda63 100644
+--- a/drivers/video/fbdev/pxafb.c
++++ b/drivers/video/fbdev/pxafb.c
+@@ -2403,6 +2403,7 @@ static void pxafb_remove(struct platform_device *dev)
+       info = &fbi->fb;
+       pxafb_overlay_exit(fbi);
++      cancel_work_sync(&fbi->task);
+       unregister_framebuffer(info);
+       pxafb_disable_controller(fbi);
+-- 
+2.43.0
+
diff --git a/queue-6.10/fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch b/queue-6.10/fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch
new file mode 100644 (file)
index 0000000..53e3112
--- /dev/null
@@ -0,0 +1,136 @@
+From 4440a200086dfcd3f1388fd63052757d5147c90e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Aug 2024 13:55:03 +0800
+Subject: fs/inode: Prevent dump_mapping() accessing invalid dentry.d_name.name
+
+From: Li Zhijian <lizhijian@fujitsu.com>
+
+[ Upstream commit 7f7b850689ac06a62befe26e1fd1806799e7f152 ]
+
+It's observed that a crash occurs during hot-remove a memory device,
+in which user is accessing the hugetlb. See calltrace as following:
+
+------------[ cut here ]------------
+WARNING: CPU: 1 PID: 14045 at arch/x86/mm/fault.c:1278 do_user_addr_fault+0x2a0/0x790
+Modules linked in: kmem device_dax cxl_mem cxl_pmem cxl_port cxl_pci dax_hmem dax_pmem nd_pmem cxl_acpi nd_btt cxl_core crc32c_intel nvme virtiofs fuse nvme_core nfit libnvdimm dm_multipath scsi_dh_rdac scsi_dh_emc s
+mirror dm_region_hash dm_log dm_mod
+CPU: 1 PID: 14045 Comm: daxctl Not tainted 6.10.0-rc2-lizhijian+ #492
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+RIP: 0010:do_user_addr_fault+0x2a0/0x790
+Code: 48 8b 00 a8 04 0f 84 b5 fe ff ff e9 1c ff ff ff 4c 89 e9 4c 89 e2 be 01 00 00 00 bf 02 00 00 00 e8 b5 ef 24 00 e9 42 fe ff ff <0f> 0b 48 83 c4 08 4c 89 ea 48 89 ee 4c 89 e7 5b 5d 41 5c 41 5d 41
+RSP: 0000:ffffc90000a575f0 EFLAGS: 00010046
+RAX: ffff88800c303600 RBX: 0000000000000000 RCX: 0000000000000000
+RDX: 0000000000001000 RSI: ffffffff82504162 RDI: ffffffff824b2c36
+RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000000 R12: ffffc90000a57658
+R13: 0000000000001000 R14: ffff88800bc2e040 R15: 0000000000000000
+FS:  00007f51cb57d880(0000) GS:ffff88807fd00000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000000000001000 CR3: 00000000072e2004 CR4: 00000000001706f0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+ <TASK>
+ ? __warn+0x8d/0x190
+ ? do_user_addr_fault+0x2a0/0x790
+ ? report_bug+0x1c3/0x1d0
+ ? handle_bug+0x3c/0x70
+ ? exc_invalid_op+0x14/0x70
+ ? asm_exc_invalid_op+0x16/0x20
+ ? do_user_addr_fault+0x2a0/0x790
+ ? exc_page_fault+0x31/0x200
+ exc_page_fault+0x68/0x200
+<...snip...>
+BUG: unable to handle page fault for address: 0000000000001000
+ #PF: supervisor read access in kernel mode
+ #PF: error_code(0x0000) - not-present page
+ PGD 800000000ad92067 P4D 800000000ad92067 PUD 7677067 PMD 0
+ Oops: Oops: 0000 [#1] PREEMPT SMP PTI
+ ---[ end trace 0000000000000000 ]---
+ BUG: unable to handle page fault for address: 0000000000001000
+ #PF: supervisor read access in kernel mode
+ #PF: error_code(0x0000) - not-present page
+ PGD 800000000ad92067 P4D 800000000ad92067 PUD 7677067 PMD 0
+ Oops: Oops: 0000 [#1] PREEMPT SMP PTI
+ CPU: 1 PID: 14045 Comm: daxctl Kdump: loaded Tainted: G        W          6.10.0-rc2-lizhijian+ #492
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+ RIP: 0010:dentry_name+0x1f4/0x440
+<...snip...>
+? dentry_name+0x2fa/0x440
+vsnprintf+0x1f3/0x4f0
+vprintk_store+0x23a/0x540
+vprintk_emit+0x6d/0x330
+_printk+0x58/0x80
+dump_mapping+0x10b/0x1a0
+? __pfx_free_object_rcu+0x10/0x10
+__dump_page+0x26b/0x3e0
+? vprintk_emit+0xe0/0x330
+? _printk+0x58/0x80
+? dump_page+0x17/0x50
+dump_page+0x17/0x50
+do_migrate_range+0x2f7/0x7f0
+? do_migrate_range+0x42/0x7f0
+? offline_pages+0x2f4/0x8c0
+offline_pages+0x60a/0x8c0
+memory_subsys_offline+0x9f/0x1c0
+? lockdep_hardirqs_on+0x77/0x100
+? _raw_spin_unlock_irqrestore+0x38/0x60
+device_offline+0xe3/0x110
+state_store+0x6e/0xc0
+kernfs_fop_write_iter+0x143/0x200
+vfs_write+0x39f/0x560
+ksys_write+0x65/0xf0
+do_syscall_64+0x62/0x130
+
+Previously, some sanity check have been done in dump_mapping() before
+the print facility parsing '%pd' though, it's still possible to run into
+an invalid dentry.d_name.name.
+
+Since dump_mapping() only needs to dump the filename only, retrieve it
+by itself in a safer way to prevent an unnecessary crash.
+
+Note that either retrieving the filename with '%pd' or
+strncpy_from_kernel_nofault(), the filename could be unreliable.
+
+Signed-off-by: Li Zhijian <lizhijian@fujitsu.com>
+Link: https://lore.kernel.org/r/20240826055503.1522320-1-lizhijian@fujitsu.com
+Reviewed-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/inode.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/fs/inode.c b/fs/inode.c
+index 3df67672986aa..aeb07c3b8f24e 100644
+--- a/fs/inode.c
++++ b/fs/inode.c
+@@ -593,6 +593,7 @@ void dump_mapping(const struct address_space *mapping)
+       struct hlist_node *dentry_first;
+       struct dentry *dentry_ptr;
+       struct dentry dentry;
++      char fname[64] = {};
+       unsigned long ino;
+       /*
+@@ -629,11 +630,14 @@ void dump_mapping(const struct address_space *mapping)
+               return;
+       }
++      if (strncpy_from_kernel_nofault(fname, dentry.d_name.name, 63) < 0)
++              strscpy(fname, "<invalid>");
+       /*
+-       * if dentry is corrupted, the %pd handler may still crash,
+-       * but it's unlikely that we reach here with a corrupt mapping
++       * Even if strncpy_from_kernel_nofault() succeeded,
++       * the fname could be unreliable
+        */
+-      pr_warn("aops:%ps ino:%lx dentry name:\"%pd\"\n", a_ops, ino, &dentry);
++      pr_warn("aops:%ps ino:%lx dentry name(?):\"%s\"\n",
++              a_ops, ino, fname);
+ }
+ void clear_inode(struct inode *inode)
+-- 
+2.43.0
+
diff --git a/queue-6.10/hid-i2c-hid-ensure-various-commands-do-not-interfere.patch b/queue-6.10/hid-i2c-hid-ensure-various-commands-do-not-interfere.patch
new file mode 100644 (file)
index 0000000..a003b15
--- /dev/null
@@ -0,0 +1,130 @@
+From 739f139d34f66b21dfb3d65ec7c99173ec0b0c35 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Sep 2024 13:37:40 -0700
+Subject: HID: i2c-hid: ensure various commands do not interfere with each
+ other
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+[ Upstream commit b4ed18a3d56eabd18cfd9841ff05111e3cfbe8f9 ]
+
+i2c-hid uses 2 shared buffers: command and "raw" input buffer for
+sending requests to peripherals and read data from peripherals when
+executing variety of commands. Such commands include reading of HID
+registers, requesting particular power mode, getting and setting
+reports and so on. Because all such requests use the same 2 buffers
+they should not execute simultaneously.
+
+Fix this by introducing "cmd_lock" mutex and acquire it whenever
+we needs to access ihid->cmdbuf or idid->rawbuf.
+
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/i2c-hid/i2c-hid-core.c | 42 +++++++++++++++++++-----------
+ 1 file changed, 27 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
+index 632eaf9e11a6b..2f8a9d3f1e861 100644
+--- a/drivers/hid/i2c-hid/i2c-hid-core.c
++++ b/drivers/hid/i2c-hid/i2c-hid-core.c
+@@ -105,6 +105,7 @@ struct i2c_hid {
+       wait_queue_head_t       wait;           /* For waiting the interrupt */
++      struct mutex            cmd_lock;       /* protects cmdbuf and rawbuf */
+       struct mutex            reset_lock;
+       struct i2chid_ops       *ops;
+@@ -220,6 +221,8 @@ static int i2c_hid_xfer(struct i2c_hid *ihid,
+ static int i2c_hid_read_register(struct i2c_hid *ihid, __le16 reg,
+                                void *buf, size_t len)
+ {
++      guard(mutex)(&ihid->cmd_lock);
++
+       *(__le16 *)ihid->cmdbuf = reg;
+       return i2c_hid_xfer(ihid, ihid->cmdbuf, sizeof(__le16), buf, len);
+@@ -252,6 +255,8 @@ static int i2c_hid_get_report(struct i2c_hid *ihid,
+       i2c_hid_dbg(ihid, "%s\n", __func__);
++      guard(mutex)(&ihid->cmd_lock);
++
+       /* Command register goes first */
+       *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+       length += sizeof(__le16);
+@@ -342,6 +347,8 @@ static int i2c_hid_set_or_send_report(struct i2c_hid *ihid,
+       if (!do_set && le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0)
+               return -ENOSYS;
++      guard(mutex)(&ihid->cmd_lock);
++
+       if (do_set) {
+               /* Command register goes first */
+               *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+@@ -384,6 +391,8 @@ static int i2c_hid_set_power_command(struct i2c_hid *ihid, int power_state)
+ {
+       size_t length;
++      guard(mutex)(&ihid->cmd_lock);
++
+       /* SET_POWER uses command register */
+       *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+       length = sizeof(__le16);
+@@ -440,25 +449,27 @@ static int i2c_hid_start_hwreset(struct i2c_hid *ihid)
+       if (ret)
+               return ret;
+-      /* Prepare reset command. Command register goes first. */
+-      *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+-      length += sizeof(__le16);
+-      /* Next is RESET command itself */
+-      length += i2c_hid_encode_command(ihid->cmdbuf + length,
+-                                       I2C_HID_OPCODE_RESET, 0, 0);
++      scoped_guard(mutex, &ihid->cmd_lock) {
++              /* Prepare reset command. Command register goes first. */
++              *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
++              length += sizeof(__le16);
++              /* Next is RESET command itself */
++              length += i2c_hid_encode_command(ihid->cmdbuf + length,
++                                               I2C_HID_OPCODE_RESET, 0, 0);
+-      set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
++              set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+-      ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
+-      if (ret) {
+-              dev_err(&ihid->client->dev,
+-                      "failed to reset device: %d\n", ret);
+-              goto err_clear_reset;
+-      }
++              ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
++              if (ret) {
++                      dev_err(&ihid->client->dev,
++                              "failed to reset device: %d\n", ret);
++                      break;
++              }
+-      return 0;
++              return 0;
++      }
+-err_clear_reset:
++      /* Clean up if sending reset command failed */
+       clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+       i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
+       return ret;
+@@ -1200,6 +1211,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
+       ihid->is_panel_follower = drm_is_panel_follower(&client->dev);
+       init_waitqueue_head(&ihid->wait);
++      mutex_init(&ihid->cmd_lock);
+       mutex_init(&ihid->reset_lock);
+       INIT_WORK(&ihid->panel_follower_prepare_work, ihid_core_panel_prepare_work);
+-- 
+2.43.0
+
diff --git a/queue-6.10/hid-ignore-battery-for-all-elan-i2c-hid-devices.patch b/queue-6.10/hid-ignore-battery-for-all-elan-i2c-hid-devices.patch
new file mode 100644 (file)
index 0000000..245928a
--- /dev/null
@@ -0,0 +1,126 @@
+From 63ca16d492ef1a3ee1d959bbabdee64bd57d1294 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Aug 2024 16:51:47 +0200
+Subject: HID: Ignore battery for all ELAN I2C-HID devices
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit bcc31692a1d1e21f0d06c5f727c03ee299d2264e ]
+
+Before this change there were 16 vid:pid based quirks to ignore the battery
+reported by Elan I2C-HID touchscreens on various Asus and HP laptops.
+
+And a report has been received that the 04F3:2A00 I2C touchscreen on
+the HP ProBook x360 11 G5 EE/86CF also reports a non present battery.
+
+Since I2C-HID devices are always builtin to laptops they are not battery
+owered so it should be safe to just ignore the battery on all Elan I2C-HID
+devices, rather then adding a 17th quirk for the 04F3:2A00 touchscreen.
+
+As reported in the changelog of commit a3a5a37efba1 ("HID: Ignore battery
+for ELAN touchscreens 2F2C and 4116"), which added 2 new Elan touchscreen
+quirks about a month ago, the HID reported battery seems to be related
+to a stylus being used. But even when a stylus is in use it does not
+properly report the charge of the stylus battery, instead the reported
+battery charge jumps from 0% to 1%. So it is best to just ignore the
+HID battery.
+
+Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2302776
+Cc: Louis Dalibard <ontake@ontake.dev>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-ids.h   | 16 ----------------
+ drivers/hid/hid-input.c | 37 +++++--------------------------------
+ 2 files changed, 5 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index 781c5aa298598..53655f81d9950 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -417,24 +417,8 @@
+ #define USB_DEVICE_ID_TOSHIBA_CLICK_L9W       0x0401
+ #define USB_DEVICE_ID_HP_X2           0x074d
+ #define USB_DEVICE_ID_HP_X2_10_COVER  0x0755
+-#define I2C_DEVICE_ID_HP_ENVY_X360_15 0x2d05
+-#define I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100  0x29CF
+-#define I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV   0x2CF9
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_15      0x2817
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG  0x29DF
+-#define I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN 0x2BC8
+-#define I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN 0x2C82
+-#define I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN 0x2F2C
+-#define I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN 0x4116
+ #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN        0x2544
+ #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN  0x2706
+-#define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN  0x261A
+-#define I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN 0x2A1C
+-#define I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN    0x279F
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100       0x29F5
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1    0x2BED
+-#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2    0x2BEE
+-#define I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG                0x2D02
+ #define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM       0x2F81
+ #define USB_VENDOR_ID_ELECOM          0x056e
+diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
+index c9094a4f281e9..fda9dce3da998 100644
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -373,14 +373,6 @@ static const struct hid_device_id hid_battery_quirks[] = {
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
+               USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
+         HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_GV301RA_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX3402_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_UX6404_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
+         HID_BATTERY_QUIRK_IGNORE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
+@@ -391,32 +383,13 @@ static const struct hid_device_id hid_battery_quirks[] = {
+         HID_BATTERY_QUIRK_AVOID_QUERY },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
+         HID_BATTERY_QUIRK_AVOID_QUERY },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2),
+-        HID_BATTERY_QUIRK_IGNORE },
+-      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG),
+-        HID_BATTERY_QUIRK_IGNORE },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
+         HID_BATTERY_QUIRK_AVOID_QUERY },
++      /*
++       * Elan I2C-HID touchscreens seem to all report a non present battery,
++       * set HID_BATTERY_QUIRK_IGNORE for all Elan I2C-HID devices.
++       */
++      { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE },
+       {}
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.10/hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch b/queue-6.10/hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch
new file mode 100644 (file)
index 0000000..baf69e9
--- /dev/null
@@ -0,0 +1,54 @@
+From 47d3956433b7cfc2f62e8c8f1486ba8ac19928bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 18 Aug 2024 16:27:29 +0900
+Subject: HID: multitouch: Add support for Thinkpad X12 Gen 2 Kbd Portfolio
+
+From: Vishnu Sankar <vishnuocv@gmail.com>
+
+[ Upstream commit 65b72ea91a257a5f0cb5a26b01194d3dd4b85298 ]
+
+This applies similar quirks used by previous generation device, so that
+Trackpoint and buttons on the touchpad works.  New USB KBD PID 0x61AE for
+Thinkpad X12 Tab is added.
+
+Signed-off-by: Vishnu Sankar <vishnuocv@gmail.com>
+Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-ids.h        | 1 +
+ drivers/hid/hid-multitouch.c | 6 ++++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index 53655f81d9950..06104a4e0fdc1 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -794,6 +794,7 @@
+ #define USB_DEVICE_ID_LENOVO_X1_TAB   0x60a3
+ #define USB_DEVICE_ID_LENOVO_X1_TAB3  0x60b5
+ #define USB_DEVICE_ID_LENOVO_X12_TAB  0x60fe
++#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
+ #define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E   0x600e
+ #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D    0x608d
+ #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019    0x6019
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 99812c0f830b5..c4a6908bbe540 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -2113,6 +2113,12 @@ static const struct hid_device_id mt_devices[] = {
+                          USB_VENDOR_ID_LENOVO,
+                          USB_DEVICE_ID_LENOVO_X12_TAB) },
++      /* Lenovo X12 TAB Gen 2 */
++      { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU,
++              HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
++                         USB_VENDOR_ID_LENOVO,
++                         USB_DEVICE_ID_LENOVO_X12_TAB2) },
++
+       /* Logitech devices */
+       { .driver_data = MT_CLS_NSMU,
+               HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,
+-- 
+2.43.0
+
diff --git a/queue-6.10/hwmon-nct6775-add-g15cf-to-asus-wmi-monitoring-list.patch b/queue-6.10/hwmon-nct6775-add-g15cf-to-asus-wmi-monitoring-list.patch
new file mode 100644 (file)
index 0000000..2342b00
--- /dev/null
@@ -0,0 +1,39 @@
+From d52ab9c4b7a578238c64e413ccf1346a91a3bc68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Aug 2024 18:26:38 +0300
+Subject: hwmon: (nct6775) add G15CF to ASUS WMI monitoring list
+
+From: Denis Pauk <pauk.denis@gmail.com>
+
+[ Upstream commit 1f432e4cf1dd3ecfec5ed80051b4611632a0fd51 ]
+
+Boards G15CF has got a nct6775 chip, but by default there's no use of it
+because of resource conflict with WMI method.
+
+Add the board to the WMI monitoring list.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=204807
+Signed-off-by: Denis Pauk <pauk.denis@gmail.com>
+Tested-by: Attila <attila@fulop.one>
+Message-ID: <20240812152652.1303-1-pauk.denis@gmail.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/nct6775-platform.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
+index 9aa4dcf4a6f33..096f1daa8f2bc 100644
+--- a/drivers/hwmon/nct6775-platform.c
++++ b/drivers/hwmon/nct6775-platform.c
+@@ -1269,6 +1269,7 @@ static const char * const asus_msi_boards[] = {
+       "EX-B760M-V5 D4",
+       "EX-H510M-V3",
+       "EX-H610M-V3 D4",
++      "G15CF",
+       "PRIME A620M-A",
+       "PRIME B560-PLUS",
+       "PRIME B560-PLUS AC-HES",
+-- 
+2.43.0
+
diff --git a/queue-6.10/ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch b/queue-6.10/ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch
new file mode 100644 (file)
index 0000000..b90e8a8
--- /dev/null
@@ -0,0 +1,61 @@
+From b3788b864f693d2888ddd6c742c5ac771278309e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 15:39:49 +0300
+Subject: ice: Adjust over allocation of memory in ice_sched_add_root_node()
+ and ice_sched_add_node()
+
+From: Aleksandr Mishin <amishin@t-argos.ru>
+
+[ Upstream commit 62fdaf9e8056e9a9e6fe63aa9c816ec2122d60c6 ]
+
+In ice_sched_add_root_node() and ice_sched_add_node() there are calls to
+devm_kcalloc() in order to allocate memory for array of pointers to
+'ice_sched_node' structure. But incorrect types are used as sizeof()
+arguments in these calls (structures instead of pointers) which leads to
+over allocation of memory.
+
+Adjust over allocation of memory by correcting types in devm_kcalloc()
+sizeof() arguments.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_sched.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
+index ecf8f5d602921..6ca13c5dcb14e 100644
+--- a/drivers/net/ethernet/intel/ice/ice_sched.c
++++ b/drivers/net/ethernet/intel/ice/ice_sched.c
+@@ -28,9 +28,8 @@ ice_sched_add_root_node(struct ice_port_info *pi,
+       if (!root)
+               return -ENOMEM;
+-      /* coverity[suspicious_sizeof] */
+       root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0],
+-                                    sizeof(*root), GFP_KERNEL);
++                                    sizeof(*root->children), GFP_KERNEL);
+       if (!root->children) {
+               devm_kfree(ice_hw_to_dev(hw), root);
+               return -ENOMEM;
+@@ -186,10 +185,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer,
+       if (!node)
+               return -ENOMEM;
+       if (hw->max_children[layer]) {
+-              /* coverity[suspicious_sizeof] */
+               node->children = devm_kcalloc(ice_hw_to_dev(hw),
+                                             hw->max_children[layer],
+-                                            sizeof(*node), GFP_KERNEL);
++                                            sizeof(*node->children), GFP_KERNEL);
+               if (!node->children) {
+                       devm_kfree(ice_hw_to_dev(hw), node);
+                       return -ENOMEM;
+-- 
+2.43.0
+
diff --git a/queue-6.10/iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch b/queue-6.10/iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch
new file mode 100644 (file)
index 0000000..71fcdb7
--- /dev/null
@@ -0,0 +1,49 @@
+From cc962e0f2acb2fbb394be46d69e316e002c4cf61 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Sep 2024 07:39:03 +0300
+Subject: iomap: handle a post-direct I/O invalidate race in
+ iomap_write_delalloc_release
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 7a9d43eace888a0ee6095035997bb138425844d3 ]
+
+When direct I/O completions invalidates the page cache it holds neither the
+i_rwsem nor the invalidate_lock so it can be racing with
+iomap_write_delalloc_release.  If the search for the end of the region that
+contains data returns the start offset we hit such a race and just need to
+look for the end of the newly created hole instead.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/20240910043949.3481298-2-hch@lst.de
+Reviewed-by: Darrick J. Wong <djwong@kernel.org>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/iomap/buffered-io.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
+index e817564e80e01..b9b035a5e7793 100644
+--- a/fs/iomap/buffered-io.c
++++ b/fs/iomap/buffered-io.c
+@@ -1226,7 +1226,15 @@ static int iomap_write_delalloc_release(struct inode *inode,
+                       error = data_end;
+                       goto out_unlock;
+               }
+-              WARN_ON_ONCE(data_end <= start_byte);
++
++              /*
++               * If we race with post-direct I/O invalidation of the page cache,
++               * there might be no data left at start_byte.
++               */
++              if (data_end == start_byte)
++                      continue;
++
++              WARN_ON_ONCE(data_end < start_byte);
+               WARN_ON_ONCE(data_end > scan_end_byte);
+               error = iomap_write_delalloc_scan(inode, &punch_start_byte,
+-- 
+2.43.0
+
diff --git a/queue-6.10/iommu-arm-smmu-v3-do-not-use-devm-for-the-cd-table-a.patch b/queue-6.10/iommu-arm-smmu-v3-do-not-use-devm-for-the-cd-table-a.patch
new file mode 100644 (file)
index 0000000..c9451bb
--- /dev/null
@@ -0,0 +1,103 @@
+From 506b47157936f2319779a4e56bea3fb8168799c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 12:47:52 -0300
+Subject: iommu/arm-smmu-v3: Do not use devm for the cd table allocations
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 47b2de35cab2b683f69d03515c2658c2d8515323 ]
+
+The master->cd_table is entirely contained within the struct
+arm_smmu_master which is guaranteed to be freed by the core code under
+arm_smmu_release_device().
+
+There is no reason to use devm here, arm_smmu_free_cd_tables() is reliably
+called to free the CD related memory. Remove it and save some memory.
+
+Tested-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Link: https://lore.kernel.org/r/5-v4-6416877274e1+1af-smmuv3_tidy_jgg@nvidia.com
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 29 +++++++++------------
+ 1 file changed, 13 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index 1f38669b711d3..a5425519fecb8 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -1173,8 +1173,8 @@ static int arm_smmu_alloc_cd_leaf_table(struct arm_smmu_device *smmu,
+ {
+       size_t size = CTXDESC_L2_ENTRIES * (CTXDESC_CD_DWORDS << 3);
+-      l1_desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
+-                                           &l1_desc->l2ptr_dma, GFP_KERNEL);
++      l1_desc->l2ptr = dma_alloc_coherent(smmu->dev, size,
++                                          &l1_desc->l2ptr_dma, GFP_KERNEL);
+       if (!l1_desc->l2ptr) {
+               dev_warn(smmu->dev,
+                        "failed to allocate context descriptor table\n");
+@@ -1373,17 +1373,17 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
+               cd_table->num_l1_ents = DIV_ROUND_UP(max_contexts,
+                                                 CTXDESC_L2_ENTRIES);
+-              cd_table->l1_desc = devm_kcalloc(smmu->dev, cd_table->num_l1_ents,
+-                                            sizeof(*cd_table->l1_desc),
+-                                            GFP_KERNEL);
++              cd_table->l1_desc = kcalloc(cd_table->num_l1_ents,
++                                          sizeof(*cd_table->l1_desc),
++                                          GFP_KERNEL);
+               if (!cd_table->l1_desc)
+                       return -ENOMEM;
+               l1size = cd_table->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3);
+       }
+-      cd_table->cdtab = dmam_alloc_coherent(smmu->dev, l1size, &cd_table->cdtab_dma,
+-                                         GFP_KERNEL);
++      cd_table->cdtab = dma_alloc_coherent(smmu->dev, l1size,
++                                           &cd_table->cdtab_dma, GFP_KERNEL);
+       if (!cd_table->cdtab) {
+               dev_warn(smmu->dev, "failed to allocate context descriptor\n");
+               ret = -ENOMEM;
+@@ -1394,7 +1394,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
+ err_free_l1:
+       if (cd_table->l1_desc) {
+-              devm_kfree(smmu->dev, cd_table->l1_desc);
++              kfree(cd_table->l1_desc);
+               cd_table->l1_desc = NULL;
+       }
+       return ret;
+@@ -1414,21 +1414,18 @@ static void arm_smmu_free_cd_tables(struct arm_smmu_master *master)
+                       if (!cd_table->l1_desc[i].l2ptr)
+                               continue;
+-                      dmam_free_coherent(smmu->dev, size,
+-                                         cd_table->l1_desc[i].l2ptr,
+-                                         cd_table->l1_desc[i].l2ptr_dma);
++                      dma_free_coherent(smmu->dev, size,
++                                        cd_table->l1_desc[i].l2ptr,
++                                        cd_table->l1_desc[i].l2ptr_dma);
+               }
+-              devm_kfree(smmu->dev, cd_table->l1_desc);
+-              cd_table->l1_desc = NULL;
++              kfree(cd_table->l1_desc);
+               l1size = cd_table->num_l1_ents * (CTXDESC_L1_DESC_DWORDS << 3);
+       } else {
+               l1size = cd_table->num_l1_ents * (CTXDESC_CD_DWORDS << 3);
+       }
+-      dmam_free_coherent(smmu->dev, l1size, cd_table->cdtab, cd_table->cdtab_dma);
+-      cd_table->cdtab_dma = 0;
+-      cd_table->cdtab = NULL;
++      dma_free_coherent(smmu->dev, l1size, cd_table->cdtab, cd_table->cdtab_dma);
+ }
+ bool arm_smmu_free_asid(struct arm_smmu_ctx_desc *cd)
+-- 
+2.43.0
+
diff --git a/queue-6.10/iommu-arm-smmu-v3-match-stall-behaviour-for-s2.patch b/queue-6.10/iommu-arm-smmu-v3-match-stall-behaviour-for-s2.patch
new file mode 100644 (file)
index 0000000..f82bc3a
--- /dev/null
@@ -0,0 +1,93 @@
+From d09bc3b95c6a1bcae51e0a4f3e48c3561d0839e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Aug 2024 11:03:47 +0000
+Subject: iommu/arm-smmu-v3: Match Stall behaviour for S2
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mostafa Saleh <smostafa@google.com>
+
+[ Upstream commit ce7cb08e22e09f43649b025c849a3ae3b80833c4 ]
+
+According to the spec (ARM IHI 0070 F.b), in
+"5.5 Fault configuration (A, R, S bits)":
+    A STE with stage 2 translation enabled and STE.S2S == 0 is
+    considered ILLEGAL if SMMU_IDR0.STALL_MODEL == 0b10.
+
+Also described in the pseudocode “SteIllegal()”
+    if STE.Config == '11x' then
+        [..]
+        if eff_idr0_stall_model == '10' && STE.S2S == '0' then
+            // stall_model forcing stall, but S2S == 0
+            return TRUE;
+
+Which means, S2S must be set when stall model is
+"ARM_SMMU_FEAT_STALL_FORCE", but currently the driver ignores that.
+
+Although, the driver can do the minimum and only set S2S for
+“ARM_SMMU_FEAT_STALL_FORCE”, it is more consistent to match S1
+behaviour, which also sets it for “ARM_SMMU_FEAT_STALL” if the
+master has requested stalls.
+
+Also, since S2 stalls are enabled now, report them to the IOMMU layer
+and for VFIO devices it will fail anyway as VFIO doesn’t register an
+iopf handler.
+
+Signed-off-by: Mostafa Saleh <smostafa@google.com>
+Link: https://lore.kernel.org/r/20240830110349.797399-2-smostafa@google.com
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 8 +++-----
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 +
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+index f456bcf1890ba..1f38669b711d3 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -1000,7 +1000,8 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
+               used_bits[2] |=
+                       cpu_to_le64(STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR |
+                                   STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI |
+-                                  STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2R);
++                                  STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2S |
++                                  STRTAB_STE_2_S2R);
+               used_bits[3] |= cpu_to_le64(STRTAB_STE_3_S2TTB_MASK);
+       }
+@@ -1629,6 +1630,7 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
+               STRTAB_STE_2_S2ENDI |
+ #endif
+               STRTAB_STE_2_S2PTW |
++              (master->stall_enabled ? STRTAB_STE_2_S2S : 0) |
+               STRTAB_STE_2_S2R);
+       target->data[3] = cpu_to_le64(pgtbl_cfg->arm_lpae_s2_cfg.vttbr &
+@@ -1722,10 +1724,6 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
+               return -EOPNOTSUPP;
+       }
+-      /* Stage-2 is always pinned at the moment */
+-      if (evt[1] & EVTQ_1_S2)
+-              return -EFAULT;
+-
+       if (!(evt[1] & EVTQ_1_STALL))
+               return -EOPNOTSUPP;
+diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+index 1242a086c9f94..d9c2f763eaba4 100644
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+@@ -264,6 +264,7 @@ struct arm_smmu_ste {
+ #define STRTAB_STE_2_S2AA64           (1UL << 51)
+ #define STRTAB_STE_2_S2ENDI           (1UL << 52)
+ #define STRTAB_STE_2_S2PTW            (1UL << 54)
++#define STRTAB_STE_2_S2S              (1UL << 57)
+ #define STRTAB_STE_2_S2R              (1UL << 58)
+ #define STRTAB_STE_3_S2TTB_MASK               GENMASK_ULL(51, 4)
+-- 
+2.43.0
+
diff --git a/queue-6.10/iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch b/queue-6.10/iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch
new file mode 100644 (file)
index 0000000..55c403b
--- /dev/null
@@ -0,0 +1,44 @@
+From d4fb37fe391a28495b9b69288dcba5dcd69e7c74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 10:27:13 +0800
+Subject: iommu/vt-d: Always reserve a domain ID for identity setup
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+[ Upstream commit 2c13012e09190174614fd6901857a1b8c199e17d ]
+
+We will use a global static identity domain. Reserve a static domain ID
+for it.
+
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
+Link: https://lore.kernel.org/r/20240809055431.36513-4-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/iommu.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index e9bea0305c268..eed67326976d3 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -1462,10 +1462,10 @@ static int iommu_init_domains(struct intel_iommu *iommu)
+        * entry for first-level or pass-through translation modes should
+        * be programmed with a domain id different from those used for
+        * second-level or nested translation. We reserve a domain id for
+-       * this purpose.
++       * this purpose. This domain id is also used for identity domain
++       * in legacy mode.
+        */
+-      if (sm_supported(iommu))
+-              set_bit(FLPT_DEFAULT_DID, iommu->domain_ids);
++      set_bit(FLPT_DEFAULT_DID, iommu->domain_ids);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch b/queue-6.10/iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch
new file mode 100644 (file)
index 0000000..b0a701a
--- /dev/null
@@ -0,0 +1,128 @@
+From fa7afc980c224a064fab1c9b906f095eb1a82bb2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 10:27:18 +0800
+Subject: iommu/vt-d: Fix potential lockup if qi_submit_sync called with 0
+ count
+
+From: Sanjay K Kumar <sanjay.k.kumar@intel.com>
+
+[ Upstream commit 3cf74230c139f208b7fb313ae0054386eee31a81 ]
+
+If qi_submit_sync() is invoked with 0 invalidation descriptors (for
+instance, for DMA draining purposes), we can run into a bug where a
+submitting thread fails to detect the completion of invalidation_wait.
+Subsequently, this led to a soft lockup. Currently, there is no impact
+by this bug on the existing users because no callers are submitting
+invalidations with 0 descriptors. This fix will enable future users
+(such as DMA drain) calling qi_submit_sync() with 0 count.
+
+Suppose thread T1 invokes qi_submit_sync() with non-zero descriptors, while
+concurrently, thread T2 calls qi_submit_sync() with zero descriptors. Both
+threads then enter a while loop, waiting for their respective descriptors
+to complete. T1 detects its completion (i.e., T1's invalidation_wait status
+changes to QI_DONE by HW) and proceeds to call reclaim_free_desc() to
+reclaim all descriptors, potentially including adjacent ones of other
+threads that are also marked as QI_DONE.
+
+During this time, while T2 is waiting to acquire the qi->q_lock, the IOMMU
+hardware may complete the invalidation for T2, setting its status to
+QI_DONE. However, if T1's execution of reclaim_free_desc() frees T2's
+invalidation_wait descriptor and changes its status to QI_FREE, T2 will
+not observe the QI_DONE status for its invalidation_wait and will
+indefinitely remain stuck.
+
+This soft lockup does not occur when only non-zero descriptors are
+submitted.In such cases, invalidation descriptors are interspersed among
+wait descriptors with the status QI_IN_USE, acting as barriers. These
+barriers prevent the reclaim code from mistakenly freeing descriptors
+belonging to other submitters.
+
+Considered the following example timeline:
+       T1                      T2
+========================================
+       ID1
+       WD1
+       while(WD1!=QI_DONE)
+       unlock
+                               lock
+       WD1=QI_DONE*            WD2
+                               while(WD2!=QI_DONE)
+                               unlock
+       lock
+       WD1==QI_DONE?
+       ID1=QI_DONE             WD2=DONE*
+       reclaim()
+       ID1=FREE
+       WD1=FREE
+       WD2=FREE
+       unlock
+                               soft lockup! T2 never sees QI_DONE in WD2
+
+Where:
+ID = invalidation descriptor
+WD = wait descriptor
+* Written by hardware
+
+The root of the problem is that the descriptor status QI_DONE flag is used
+for two conflicting purposes:
+1. signal a descriptor is ready for reclaim (to be freed)
+2. signal by the hardware that a wait descriptor is complete
+
+The solution (in this patch) is state separation by using QI_FREE flag
+for #1.
+
+Once a thread's invalidation descriptors are complete, their status would
+be set to QI_FREE. The reclaim_free_desc() function would then only
+free descriptors marked as QI_FREE instead of those marked as
+QI_DONE. This change ensures that T2 (from the previous example) will
+correctly observe the completion of its invalidation_wait (marked as
+QI_DONE).
+
+Signed-off-by: Sanjay K Kumar <sanjay.k.kumar@intel.com>
+Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Link: https://lore.kernel.org/r/20240728210059.1964602-1-jacob.jun.pan@linux.intel.com
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/dmar.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
+index 1c8d3141cb55c..01e157d89a163 100644
+--- a/drivers/iommu/intel/dmar.c
++++ b/drivers/iommu/intel/dmar.c
+@@ -1204,9 +1204,7 @@ static void free_iommu(struct intel_iommu *iommu)
+  */
+ static inline void reclaim_free_desc(struct q_inval *qi)
+ {
+-      while (qi->desc_status[qi->free_tail] == QI_DONE ||
+-             qi->desc_status[qi->free_tail] == QI_ABORT) {
+-              qi->desc_status[qi->free_tail] = QI_FREE;
++      while (qi->desc_status[qi->free_tail] == QI_FREE && qi->free_tail != qi->free_head) {
+               qi->free_tail = (qi->free_tail + 1) % QI_LENGTH;
+               qi->free_cnt++;
+       }
+@@ -1463,8 +1461,16 @@ int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc,
+               raw_spin_lock(&qi->q_lock);
+       }
+-      for (i = 0; i < count; i++)
+-              qi->desc_status[(index + i) % QI_LENGTH] = QI_DONE;
++      /*
++       * The reclaim code can free descriptors from multiple submissions
++       * starting from the tail of the queue. When count == 0, the
++       * status of the standalone wait descriptor at the tail of the queue
++       * must be set to QI_FREE to allow the reclaim code to proceed.
++       * It is also possible that descriptors from one of the previous
++       * submissions has to be reclaimed by a subsequent submission.
++       */
++      for (i = 0; i <= count; i++)
++              qi->desc_status[(index + i) % QI_LENGTH] = QI_FREE;
+       reclaim_free_desc(qi);
+       raw_spin_unlock_irqrestore(&qi->q_lock, flags);
+-- 
+2.43.0
+
diff --git a/queue-6.10/iommu-vt-d-unconditionally-flush-device-tlb-for-pasi.patch b/queue-6.10/iommu-vt-d-unconditionally-flush-device-tlb-for-pasi.patch
new file mode 100644 (file)
index 0000000..7a63e87
--- /dev/null
@@ -0,0 +1,70 @@
+From 650f16adf17f37178fd7a66be0448d0f57232896 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 10:27:20 +0800
+Subject: iommu/vt-d: Unconditionally flush device TLB for pasid table updates
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+[ Upstream commit 1f5e307ca16c0c19186cbd56ac460a687e6daba0 ]
+
+The caching mode of an IOMMU is irrelevant to the behavior of the device
+TLB. Previously, commit <304b3bde24b5> ("iommu/vt-d: Remove caching mode
+check before device TLB flush") removed this redundant check in the
+domain unmap path.
+
+Checking the caching mode before flushing the device TLB after a pasid
+table entry is updated is unnecessary and can lead to inconsistent
+behavior.
+
+Extends this consistency by removing the caching mode check in the pasid
+table update path.
+
+Suggested-by: Yi Liu <yi.l.liu@intel.com>
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Link: https://lore.kernel.org/r/20240820030208.20020-1-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/intel/pasid.c | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
+index aabcdf7565817..57dd3530f68d4 100644
+--- a/drivers/iommu/intel/pasid.c
++++ b/drivers/iommu/intel/pasid.c
+@@ -261,9 +261,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
+       else
+               iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
+-      /* Device IOTLB doesn't need to be flushed in caching mode. */
+-      if (!cap_caching_mode(iommu->cap))
+-              devtlb_invalidation_with_pasid(iommu, dev, pasid);
++      devtlb_invalidation_with_pasid(iommu, dev, pasid);
+ }
+ /*
+@@ -490,9 +488,7 @@ int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
+       iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
+-      /* Device IOTLB doesn't need to be flushed in caching mode. */
+-      if (!cap_caching_mode(iommu->cap))
+-              devtlb_invalidation_with_pasid(iommu, dev, pasid);
++      devtlb_invalidation_with_pasid(iommu, dev, pasid);
+       return 0;
+ }
+@@ -569,9 +565,7 @@ void intel_pasid_setup_page_snoop_control(struct intel_iommu *iommu,
+       pasid_cache_invalidation_with_pasid(iommu, did, pasid);
+       qi_flush_piotlb(iommu, did, pasid, 0, -1, 0);
+-      /* Device IOTLB doesn't need to be flushed in caching mode. */
+-      if (!cap_caching_mode(iommu->cap))
+-              devtlb_invalidation_with_pasid(iommu, dev, pasid);
++      devtlb_invalidation_with_pasid(iommu, dev, pasid);
+ }
+ /**
+-- 
+2.43.0
+
diff --git a/queue-6.10/ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch b/queue-6.10/ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch
new file mode 100644 (file)
index 0000000..35b174a
--- /dev/null
@@ -0,0 +1,52 @@
+From d1700d76af7f427e715be75551db719a5090102f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Aug 2024 16:54:02 -0700
+Subject: ipv4: Check !in_dev earlier for ioctl(SIOCSIFADDR).
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit e3af3d3c5b26c33a7950e34e137584f6056c4319 ]
+
+dev->ip_ptr could be NULL if we set an invalid MTU.
+
+Even then, if we issue ioctl(SIOCSIFADDR) for a new IPv4 address,
+devinet_ioctl() allocates struct in_ifaddr and fails later in
+inet_set_ifa() because in_dev is NULL.
+
+Let's move the check earlier.
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20240809235406.50187-2-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/devinet.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index d09f557eaa779..73effd2d2994a 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -574,10 +574,6 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
+       ASSERT_RTNL();
+-      if (!in_dev) {
+-              inet_free_ifa(ifa);
+-              return -ENOBUFS;
+-      }
+       ipv4_devconf_setall(in_dev);
+       neigh_parms_data_state_setall(in_dev->arp_parms);
+       if (ifa->ifa_dev != in_dev) {
+@@ -1184,6 +1180,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
+               if (!ifa) {
+                       ret = -ENOBUFS;
++                      if (!in_dev)
++                              break;
+                       ifa = inet_alloc_ifa();
+                       if (!ifa)
+                               break;
+-- 
+2.43.0
+
diff --git a/queue-6.10/ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch b/queue-6.10/ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch
new file mode 100644 (file)
index 0000000..946740f
--- /dev/null
@@ -0,0 +1,50 @@
+From b2409888d74e3c40100804867972aac8a9626697 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Aug 2024 15:52:22 +0300
+Subject: ipv4: Mask upper DSCP bits and ECN bits in NETLINK_FIB_LOOKUP family
+
+From: Ido Schimmel <idosch@nvidia.com>
+
+[ Upstream commit 8fed54758cd248cd311a2b5c1e180abef1866237 ]
+
+The NETLINK_FIB_LOOKUP netlink family can be used to perform a FIB
+lookup according to user provided parameters and communicate the result
+back to user space.
+
+However, unlike other users of the FIB lookup API, the upper DSCP bits
+and the ECN bits of the DS field are not masked, which can result in the
+wrong result being returned.
+
+Solve this by masking the upper DSCP bits and the ECN bits using
+IPTOS_RT_MASK.
+
+The structure that communicates the request and the response is not
+exported to user space, so it is unlikely that this netlink family is
+actually in use [1].
+
+[1] https://lore.kernel.org/netdev/ZpqpB8vJU%2FQ6LSqa@debian/
+
+Signed-off-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Guillaume Nault <gnault@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/fib_frontend.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index 7ad2cafb92763..da540ddb7af65 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -1343,7 +1343,7 @@ static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
+       struct flowi4           fl4 = {
+               .flowi4_mark = frn->fl_mark,
+               .daddr = frn->fl_addr,
+-              .flowi4_tos = frn->fl_tos,
++              .flowi4_tos = frn->fl_tos & IPTOS_RT_MASK,
+               .flowi4_scope = frn->fl_scope,
+       };
+       struct fib_table *tb;
+-- 
+2.43.0
+
diff --git a/queue-6.10/jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch b/queue-6.10/jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch
new file mode 100644 (file)
index 0000000..27eb17a
--- /dev/null
@@ -0,0 +1,52 @@
+From ed3814699d296976778712cef1bd3ca3406d88bd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 24 Aug 2024 09:25:23 +0800
+Subject: jfs: check if leafidx greater than num leaves per dmap tree
+
+From: Edward Adam Davis <eadavis@qq.com>
+
+[ Upstream commit d64ff0d2306713ff084d4b09f84ed1a8c75ecc32 ]
+
+syzbot report a out of bounds in dbSplit, it because dmt_leafidx greater
+than num leaves per dmap tree, add a checking for dmt_leafidx in dbFindLeaf.
+
+Shaggy:
+Modified sanity check to apply to control pages as well as leaf pages.
+
+Reported-and-tested-by: syzbot+dca05492eff41f604890@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=dca05492eff41f604890
+Signed-off-by: Edward Adam Davis <eadavis@qq.com>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/jfs_dmap.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
+index 8847e8c5d5b45..974ecf5e0d952 100644
+--- a/fs/jfs/jfs_dmap.c
++++ b/fs/jfs/jfs_dmap.c
+@@ -2944,9 +2944,10 @@ static void dbAdjTree(dmtree_t *tp, int leafno, int newval, bool is_ctl)
+ static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl)
+ {
+       int ti, n = 0, k, x = 0;
+-      int max_size;
++      int max_size, max_idx;
+       max_size = is_ctl ? CTLTREESIZE : TREESIZE;
++      max_idx = is_ctl ? LPERCTL : LPERDMAP;
+       /* first check the root of the tree to see if there is
+        * sufficient free space.
+@@ -2978,6 +2979,8 @@ static int dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx, bool is_ctl)
+                */
+               assert(n < 4);
+       }
++      if (le32_to_cpu(tp->dmt_leafidx) >= max_idx)
++              return -ENOSPC;
+       /* set the return to the leftmost leaf describing sufficient
+        * free space.
+-- 
+2.43.0
+
diff --git a/queue-6.10/jfs-fix-uaf-in-dbfreebits.patch b/queue-6.10/jfs-fix-uaf-in-dbfreebits.patch
new file mode 100644 (file)
index 0000000..c62da28
--- /dev/null
@@ -0,0 +1,117 @@
+From 9a08cd131f6f2a683c63f3a64af7609874c60460 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 24 Aug 2024 10:50:48 +0800
+Subject: jfs: Fix uaf in dbFreeBits
+
+From: Edward Adam Davis <eadavis@qq.com>
+
+[ Upstream commit d6c1b3599b2feb5c7291f5ac3a36e5fa7cedb234 ]
+
+[syzbot reported]
+==================================================================
+BUG: KASAN: slab-use-after-free in __mutex_lock_common kernel/locking/mutex.c:587 [inline]
+BUG: KASAN: slab-use-after-free in __mutex_lock+0xfe/0xd70 kernel/locking/mutex.c:752
+Read of size 8 at addr ffff8880229254b0 by task syz-executor357/5216
+
+CPU: 0 UID: 0 PID: 5216 Comm: syz-executor357 Not tainted 6.11.0-rc3-syzkaller-00156-gd7a5aa4b3c00 #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/27/2024
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:93 [inline]
+ dump_stack_lvl+0x241/0x360 lib/dump_stack.c:119
+ print_address_description mm/kasan/report.c:377 [inline]
+ print_report+0x169/0x550 mm/kasan/report.c:488
+ kasan_report+0x143/0x180 mm/kasan/report.c:601
+ __mutex_lock_common kernel/locking/mutex.c:587 [inline]
+ __mutex_lock+0xfe/0xd70 kernel/locking/mutex.c:752
+ dbFreeBits+0x7ea/0xd90 fs/jfs/jfs_dmap.c:2390
+ dbFreeDmap fs/jfs/jfs_dmap.c:2089 [inline]
+ dbFree+0x35b/0x680 fs/jfs/jfs_dmap.c:409
+ dbDiscardAG+0x8a9/0xa20 fs/jfs/jfs_dmap.c:1650
+ jfs_ioc_trim+0x433/0x670 fs/jfs/jfs_discard.c:100
+ jfs_ioctl+0x2d0/0x3e0 fs/jfs/ioctl.c:131
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:907 [inline]
+ __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:893
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+
+Freed by task 5218:
+ kasan_save_stack mm/kasan/common.c:47 [inline]
+ kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
+ kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:579
+ poison_slab_object+0xe0/0x150 mm/kasan/common.c:240
+ __kasan_slab_free+0x37/0x60 mm/kasan/common.c:256
+ kasan_slab_free include/linux/kasan.h:184 [inline]
+ slab_free_hook mm/slub.c:2252 [inline]
+ slab_free mm/slub.c:4473 [inline]
+ kfree+0x149/0x360 mm/slub.c:4594
+ dbUnmount+0x11d/0x190 fs/jfs/jfs_dmap.c:278
+ jfs_mount_rw+0x4ac/0x6a0 fs/jfs/jfs_mount.c:247
+ jfs_remount+0x3d1/0x6b0 fs/jfs/super.c:454
+ reconfigure_super+0x445/0x880 fs/super.c:1083
+ vfs_cmd_reconfigure fs/fsopen.c:263 [inline]
+ vfs_fsconfig_locked fs/fsopen.c:292 [inline]
+ __do_sys_fsconfig fs/fsopen.c:473 [inline]
+ __se_sys_fsconfig+0xb6e/0xf80 fs/fsopen.c:345
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+[Analysis]
+There are two paths (dbUnmount and jfs_ioc_trim) that generate race
+condition when accessing bmap, which leads to the occurrence of uaf.
+
+Use the lock s_umount to synchronize them, in order to avoid uaf caused
+by race condition.
+
+Reported-and-tested-by: syzbot+3c010e21296f33a5dc16@syzkaller.appspotmail.com
+Signed-off-by: Edward Adam Davis <eadavis@qq.com>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/jfs_discard.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c
+index 575cb2ba74fc8..5f4b305030ad5 100644
+--- a/fs/jfs/jfs_discard.c
++++ b/fs/jfs/jfs_discard.c
+@@ -65,7 +65,7 @@ void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks)
+ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+ {
+       struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+-      struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
++      struct bmap *bmp;
+       struct super_block *sb = ipbmap->i_sb;
+       int agno, agno_end;
+       u64 start, end, minlen;
+@@ -83,10 +83,15 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+       if (minlen == 0)
+               minlen = 1;
++      down_read(&sb->s_umount);
++      bmp = JFS_SBI(ip->i_sb)->bmap;
++
+       if (minlen > bmp->db_agsize ||
+           start >= bmp->db_mapsize ||
+-          range->len < sb->s_blocksize)
++          range->len < sb->s_blocksize) {
++              up_read(&sb->s_umount);
+               return -EINVAL;
++      }
+       if (end >= bmp->db_mapsize)
+               end = bmp->db_mapsize - 1;
+@@ -100,6 +105,8 @@ int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+               trimmed += dbDiscardAG(ip, agno, minlen);
+               agno++;
+       }
++
++      up_read(&sb->s_umount);
+       range->len = trimmed << sb->s_blocksize_bits;
+       return 0;
+-- 
+2.43.0
+
diff --git a/queue-6.10/jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch b/queue-6.10/jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch
new file mode 100644 (file)
index 0000000..80fef0a
--- /dev/null
@@ -0,0 +1,57 @@
+From 4e3bdbb5e4b491c34e070d8fbf2bf312873854d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 09:07:58 +0800
+Subject: jfs: Fix uninit-value access of new_ea in ea_buffer
+
+From: Zhao Mengmeng <zhaomengmeng@kylinos.cn>
+
+[ Upstream commit 2b59ffad47db1c46af25ccad157bb3b25147c35c ]
+
+syzbot reports that lzo1x_1_do_compress is using uninit-value:
+
+=====================================================
+BUG: KMSAN: uninit-value in lzo1x_1_do_compress+0x19f9/0x2510 lib/lzo/lzo1x_compress.c:178
+
+...
+
+Uninit was stored to memory at:
+ ea_put fs/jfs/xattr.c:639 [inline]
+
+...
+
+Local variable ea_buf created at:
+ __jfs_setxattr+0x5d/0x1ae0 fs/jfs/xattr.c:662
+ __jfs_xattr_set+0xe6/0x1f0 fs/jfs/xattr.c:934
+
+=====================================================
+
+The reason is ea_buf->new_ea is not initialized properly.
+
+Fix this by using memset to empty its content at the beginning
+in ea_get().
+
+Reported-by: syzbot+02341e0daa42a15ce130@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=02341e0daa42a15ce130
+Signed-off-by: Zhao Mengmeng <zhaomengmeng@kylinos.cn>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/xattr.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
+index 2999ed5d83f5e..0fb05e314edf6 100644
+--- a/fs/jfs/xattr.c
++++ b/fs/jfs/xattr.c
+@@ -434,6 +434,8 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
+       int rc;
+       int quota_allocation = 0;
++      memset(&ea_buf->new_ea, 0, sizeof(ea_buf->new_ea));
++
+       /* When fsck.jfs clears a bad ea, it doesn't clear the size */
+       if (ji->ea.flag == 0)
+               ea_size = 0;
+-- 
+2.43.0
+
diff --git a/queue-6.10/jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch b/queue-6.10/jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch
new file mode 100644 (file)
index 0000000..2596f26
--- /dev/null
@@ -0,0 +1,35 @@
+From 3b066e418e9284399e809109e7755d49a917e473 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 00:12:44 +0000
+Subject: jfs: UBSAN: shift-out-of-bounds in dbFindBits
+
+From: Remington Brasga <rbrasga@uci.edu>
+
+[ Upstream commit b0b2fc815e514221f01384f39fbfbff65d897e1c ]
+
+Fix issue with UBSAN throwing shift-out-of-bounds warning.
+
+Reported-by: syzbot+e38d703eeb410b17b473@syzkaller.appspotmail.com
+Signed-off-by: Remington Brasga <rbrasga@uci.edu>
+Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jfs/jfs_dmap.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
+index 0625d1c0d0649..8847e8c5d5b45 100644
+--- a/fs/jfs/jfs_dmap.c
++++ b/fs/jfs/jfs_dmap.c
+@@ -3022,7 +3022,7 @@ static int dbFindBits(u32 word, int l2nb)
+       /* scan the word for nb free bits at nb alignments.
+        */
+-      for (bitno = 0; mask != 0; bitno += nb, mask >>= nb) {
++      for (bitno = 0; mask != 0; bitno += nb, mask = (mask >> nb)) {
+               if ((mask & word) == mask)
+                       break;
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.10/ksmbd-add-refcnt-to-ksmbd_conn-struct.patch b/queue-6.10/ksmbd-add-refcnt-to-ksmbd_conn-struct.patch
new file mode 100644 (file)
index 0000000..88f4208
--- /dev/null
@@ -0,0 +1,245 @@
+From ed22f4a307562dc43b055644a9cf43cbc19f0430 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 20:28:08 +0900
+Subject: ksmbd: add refcnt to ksmbd_conn struct
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit ee426bfb9d09b29987369b897fe9b6485ac2be27 ]
+
+When sending an oplock break request, opinfo->conn is used,
+But freed ->conn can be used on multichannel.
+This patch add a reference count to the ksmbd_conn struct
+so that it can be freed when it is no longer used.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/connection.c |  4 ++-
+ fs/smb/server/connection.h |  1 +
+ fs/smb/server/oplock.c     | 55 +++++++++++---------------------------
+ fs/smb/server/vfs_cache.c  |  3 +++
+ 4 files changed, 23 insertions(+), 40 deletions(-)
+
+diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
+index 7889df8112b4e..cac80e7bfefc7 100644
+--- a/fs/smb/server/connection.c
++++ b/fs/smb/server/connection.c
+@@ -39,7 +39,8 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
+       xa_destroy(&conn->sessions);
+       kvfree(conn->request_buf);
+       kfree(conn->preauth_info);
+-      kfree(conn);
++      if (atomic_dec_and_test(&conn->refcnt))
++              kfree(conn);
+ }
+ /**
+@@ -68,6 +69,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
+               conn->um = NULL;
+       atomic_set(&conn->req_running, 0);
+       atomic_set(&conn->r_count, 0);
++      atomic_set(&conn->refcnt, 1);
+       conn->total_credits = 1;
+       conn->outstanding_credits = 0;
+diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
+index b93e5437793e0..82343afc8d049 100644
+--- a/fs/smb/server/connection.h
++++ b/fs/smb/server/connection.h
+@@ -106,6 +106,7 @@ struct ksmbd_conn {
+       bool                            signing_negotiated;
+       __le16                          signing_algorithm;
+       bool                            binding;
++      atomic_t                        refcnt;
+ };
+ struct ksmbd_conn_ops {
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index e546ffa57b55a..8ee86478287f9 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -51,6 +51,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
+       init_waitqueue_head(&opinfo->oplock_brk);
+       atomic_set(&opinfo->refcount, 1);
+       atomic_set(&opinfo->breaking_cnt, 0);
++      atomic_inc(&opinfo->conn->refcnt);
+       return opinfo;
+ }
+@@ -124,6 +125,8 @@ static void free_opinfo(struct oplock_info *opinfo)
+ {
+       if (opinfo->is_lease)
+               free_lease(opinfo);
++      if (opinfo->conn && atomic_dec_and_test(&opinfo->conn->refcnt))
++              kfree(opinfo->conn);
+       kfree(opinfo);
+ }
+@@ -163,9 +166,7 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
+                   !atomic_inc_not_zero(&opinfo->refcount))
+                       opinfo = NULL;
+               else {
+-                      atomic_inc(&opinfo->conn->r_count);
+                       if (ksmbd_conn_releasing(opinfo->conn)) {
+-                              atomic_dec(&opinfo->conn->r_count);
+                               atomic_dec(&opinfo->refcount);
+                               opinfo = NULL;
+                       }
+@@ -177,26 +178,11 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
+       return opinfo;
+ }
+-static void opinfo_conn_put(struct oplock_info *opinfo)
++void opinfo_put(struct oplock_info *opinfo)
+ {
+-      struct ksmbd_conn *conn;
+-
+       if (!opinfo)
+               return;
+-      conn = opinfo->conn;
+-      /*
+-       * Checking waitqueue to dropping pending requests on
+-       * disconnection. waitqueue_active is safe because it
+-       * uses atomic operation for condition.
+-       */
+-      if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+-              wake_up(&conn->r_count_q);
+-      opinfo_put(opinfo);
+-}
+-
+-void opinfo_put(struct oplock_info *opinfo)
+-{
+       if (!atomic_dec_and_test(&opinfo->refcount))
+               return;
+@@ -1127,14 +1113,11 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
+                       if (!atomic_inc_not_zero(&opinfo->refcount))
+                               continue;
+-                      atomic_inc(&opinfo->conn->r_count);
+-                      if (ksmbd_conn_releasing(opinfo->conn)) {
+-                              atomic_dec(&opinfo->conn->r_count);
++                      if (ksmbd_conn_releasing(opinfo->conn))
+                               continue;
+-                      }
+                       oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
+-                      opinfo_conn_put(opinfo);
++                      opinfo_put(opinfo);
+               }
+       }
+       up_read(&p_ci->m_lock);
+@@ -1167,13 +1150,10 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
+                       if (!atomic_inc_not_zero(&opinfo->refcount))
+                               continue;
+-                      atomic_inc(&opinfo->conn->r_count);
+-                      if (ksmbd_conn_releasing(opinfo->conn)) {
+-                              atomic_dec(&opinfo->conn->r_count);
++                      if (ksmbd_conn_releasing(opinfo->conn))
+                               continue;
+-                      }
+                       oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
+-                      opinfo_conn_put(opinfo);
++                      opinfo_put(opinfo);
+               }
+       }
+       up_read(&p_ci->m_lock);
+@@ -1252,7 +1232,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
+       prev_opinfo = opinfo_get_list(ci);
+       if (!prev_opinfo ||
+           (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {
+-              opinfo_conn_put(prev_opinfo);
++              opinfo_put(prev_opinfo);
+               goto set_lev;
+       }
+       prev_op_has_lease = prev_opinfo->is_lease;
+@@ -1262,19 +1242,19 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
+       if (share_ret < 0 &&
+           prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+               err = share_ret;
+-              opinfo_conn_put(prev_opinfo);
++              opinfo_put(prev_opinfo);
+               goto err_out;
+       }
+       if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
+           prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+-              opinfo_conn_put(prev_opinfo);
++              opinfo_put(prev_opinfo);
+               goto op_break_not_needed;
+       }
+       list_add(&work->interim_entry, &prev_opinfo->interim_list);
+       err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
+-      opinfo_conn_put(prev_opinfo);
++      opinfo_put(prev_opinfo);
+       if (err == -ENOENT)
+               goto set_lev;
+       /* Check all oplock was freed by close */
+@@ -1337,14 +1317,14 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
+               return;
+       if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
+           brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+-              opinfo_conn_put(brk_opinfo);
++              opinfo_put(brk_opinfo);
+               return;
+       }
+       brk_opinfo->open_trunc = is_trunc;
+       list_add(&work->interim_entry, &brk_opinfo->interim_list);
+       oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
+-      opinfo_conn_put(brk_opinfo);
++      opinfo_put(brk_opinfo);
+ }
+ /**
+@@ -1376,11 +1356,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
+               if (!atomic_inc_not_zero(&brk_op->refcount))
+                       continue;
+-              atomic_inc(&brk_op->conn->r_count);
+-              if (ksmbd_conn_releasing(brk_op->conn)) {
+-                      atomic_dec(&brk_op->conn->r_count);
++              if (ksmbd_conn_releasing(brk_op->conn))
+                       continue;
+-              }
+               rcu_read_unlock();
+               if (brk_op->is_lease && (brk_op->o_lease->state &
+@@ -1411,7 +1388,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
+               brk_op->open_trunc = is_trunc;
+               oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
+ next:
+-              opinfo_conn_put(brk_op);
++              opinfo_put(brk_op);
+               rcu_read_lock();
+       }
+       rcu_read_unlock();
+diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
+index 8b2e37c8716ed..271a23abc82fd 100644
+--- a/fs/smb/server/vfs_cache.c
++++ b/fs/smb/server/vfs_cache.c
+@@ -710,6 +710,8 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
+       list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
+               if (op->conn != conn)
+                       continue;
++              if (op->conn && atomic_dec_and_test(&op->conn->refcnt))
++                      kfree(op->conn);
+               op->conn = NULL;
+       }
+       up_write(&ci->m_lock);
+@@ -807,6 +809,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
+               if (op->conn)
+                       continue;
+               op->conn = fp->conn;
++              atomic_inc(&op->conn->refcnt);
+       }
+       up_write(&ci->m_lock);
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-atlantic-avoid-warning-about-potential-string-tr.patch b/queue-6.10/net-atlantic-avoid-warning-about-potential-string-tr.patch
new file mode 100644 (file)
index 0000000..fb6b87b
--- /dev/null
@@ -0,0 +1,79 @@
+From 690a4340619cd10677a3173e5ded384a4f68e11f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 16:58:57 +0100
+Subject: net: atlantic: Avoid warning about potential string truncation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 5874e0c9f25661c2faefe4809907166defae3d7f ]
+
+W=1 builds with GCC 14.2.0 warn that:
+
+.../aq_ethtool.c:278:59: warning: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 6 [-Wformat-truncation=]
+  278 |                                 snprintf(tc_string, 8, "TC%d ", tc);
+      |                                                           ^~
+.../aq_ethtool.c:278:56: note: directive argument in the range [-2147483641, 254]
+  278 |                                 snprintf(tc_string, 8, "TC%d ", tc);
+      |                                                        ^~~~~~~
+.../aq_ethtool.c:278:33: note: ‘snprintf’ output between 5 and 15 bytes into a destination of size 8
+  278 |                                 snprintf(tc_string, 8, "TC%d ", tc);
+      |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+tc is always in the range 0 - cfg->tcs. And as cfg->tcs is a u8,
+the range is 0 - 255. Further, on inspecting the code, it seems
+that cfg->tcs will never be more than AQ_CFG_TCS_MAX (8), so
+the range is actually 0 - 8.
+
+So, it seems that the condition that GCC flags will not occur.
+But, nonetheless, it would be nice if it didn't emit the warning.
+
+It seems that this can be achieved by changing the format specifier
+from %d to %u, in which case I believe GCC recognises an upper bound
+on the range of tc of 0 - 255. After some experimentation I think
+this is due to the combination of the use of %u and the type of
+cfg->tcs (u8).
+
+Empirically, updating the type of the tc variable to unsigned int
+has the same effect.
+
+As both of these changes seem to make sense in relation to what the code
+is actually doing - iterating over unsigned values - do both.
+
+Compile tested only.
+
+Signed-off-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240821-atlantic-str-v1-1-fa2cfe38ca00@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+index a2606ee3b0a56..cfc413caf93f4 100644
+--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
++++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+@@ -266,7 +266,7 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
+               const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names);
+               const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names);
+               char tc_string[8];
+-              int tc;
++              unsigned int tc;
+               memset(tc_string, 0, sizeof(tc_string));
+               memcpy(p, aq_ethtool_stat_names,
+@@ -275,7 +275,7 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
+               for (tc = 0; tc < cfg->tcs; tc++) {
+                       if (cfg->is_qos)
+-                              snprintf(tc_string, 8, "TC%d ", tc);
++                              snprintf(tc_string, 8, "TC%u ", tc);
+                       for (i = 0; i < cfg->vecs; i++) {
+                               for (si = 0; si < rx_stat_cnt; si++) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-hisilicon-hip04-fix-of-node-leak-in-probe.patch b/queue-6.10/net-hisilicon-hip04-fix-of-node-leak-in-probe.patch
new file mode 100644 (file)
index 0000000..5a8aa8c
--- /dev/null
@@ -0,0 +1,36 @@
+From ee4187d12cc0991b73a17366e959525730774394 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 16:44:19 +0200
+Subject: net: hisilicon: hip04: fix OF node leak in probe()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 17555297dbd5bccc93a01516117547e26a61caf1 ]
+
+Driver is leaking OF node reference from
+of_parse_phandle_with_fixed_args() in probe().
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240827144421.52852-2-krzysztof.kozlowski@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hip04_eth.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
+index b91e7a06b97f7..beb815e5289b1 100644
+--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
++++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
+@@ -947,6 +947,7 @@ static int hip04_mac_probe(struct platform_device *pdev)
+       priv->tx_coalesce_timer.function = tx_done;
+       priv->map = syscon_node_to_regmap(arg.np);
++      of_node_put(arg.np);
+       if (IS_ERR(priv->map)) {
+               dev_warn(d, "no syscon hisilicon,hip04-ppe\n");
+               ret = PTR_ERR(priv->map);
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch b/queue-6.10/net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch
new file mode 100644 (file)
index 0000000..8df3086
--- /dev/null
@@ -0,0 +1,36 @@
+From b53f2aacf3d7ff0d4e1b8e09ffc26b1cdaf3d368 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 16:44:20 +0200
+Subject: net: hisilicon: hns_dsaf_mac: fix OF node leak in hns_mac_get_info()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 5680cf8d34e1552df987e2f4bb1bff0b2a8c8b11 ]
+
+Driver is leaking OF node reference from
+of_parse_phandle_with_fixed_args() in hns_mac_get_info().
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240827144421.52852-3-krzysztof.kozlowski@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+index f75668c479351..616a2768e5048 100644
+--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
++++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+@@ -933,6 +933,7 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
+                       mac_cb->cpld_ctrl = NULL;
+               } else {
+                       syscon = syscon_node_to_regmap(cpld_args.np);
++                      of_node_put(cpld_args.np);
+                       if (IS_ERR_OR_NULL(syscon)) {
+                               dev_dbg(mac_cb->dev, "no cpld-syscon found!\n");
+                               mac_cb->cpld_ctrl = NULL;
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch b/queue-6.10/net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch
new file mode 100644 (file)
index 0000000..e94b0d0
--- /dev/null
@@ -0,0 +1,36 @@
+From 05a07a093fe98539a4c3d3a8f1e225d21edd0828 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 16:44:21 +0200
+Subject: net: hisilicon: hns_mdio: fix OF node leak in probe()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit e62beddc45f487b9969821fad3a0913d9bc18a2f ]
+
+Driver is leaking OF node reference from
+of_parse_phandle_with_fixed_args() in probe().
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240827144421.52852-4-krzysztof.kozlowski@linaro.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/hisilicon/hns_mdio.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
+index ed73707176c1a..8a047145f0c50 100644
+--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
++++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
+@@ -575,6 +575,7 @@ static int hns_mdio_probe(struct platform_device *pdev)
+                                               MDIO_SC_RESET_ST;
+                               }
+                       }
++                      of_node_put(reg_args.np);
+               } else {
+                       dev_warn(&pdev->dev, "find syscon ret = %#x\n", ret);
+                       mdio_dev->subctrl_vbase = NULL;
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-mvpp2-increase-size-of-queue_name-buffer.patch b/queue-6.10/net-mvpp2-increase-size-of-queue_name-buffer.patch
new file mode 100644 (file)
index 0000000..00a7f38
--- /dev/null
@@ -0,0 +1,58 @@
+From bad78f6f233459730f45bcaf1be2d069e5e1c2c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Aug 2024 12:28:24 +0100
+Subject: net: mvpp2: Increase size of queue_name buffer
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 91d516d4de48532d967a77967834e00c8c53dfe6 ]
+
+Increase size of queue_name buffer from 30 to 31 to accommodate
+the largest string written to it. This avoids truncation in
+the possibly unlikely case where the string is name is the
+maximum size.
+
+Flagged by gcc-14:
+
+  .../mvpp2_main.c: In function 'mvpp2_probe':
+  .../mvpp2_main.c:7636:32: warning: 'snprintf' output may be truncated before the last format character [-Wformat-truncation=]
+   7636 |                  "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
+        |                                ^
+  .../mvpp2_main.c:7635:9: note: 'snprintf' output between 10 and 31 bytes into a destination of size 30
+   7635 |         snprintf(priv->queue_name, sizeof(priv->queue_name),
+        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   7636 |                  "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
+        |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   7637 |                  priv->port_count > 1 ? "+" : "");
+        |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Introduced by commit 118d6298f6f0 ("net: mvpp2: add ethtool GOP statistics").
+I am not flagging this as a bug as I am not aware that it is one.
+
+Compile tested only.
+
+Signed-off-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Marcin Wojtas <marcin.s.wojtas@gmail.com>
+Link: https://patch.msgid.link/20240806-mvpp2-namelen-v1-1-6dc773653f2f@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+index e809f91c08fb9..9e02e4367bec8 100644
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+@@ -1088,7 +1088,7 @@ struct mvpp2 {
+       unsigned int max_port_rxqs;
+       /* Workqueue to gather hardware statistics */
+-      char queue_name[30];
++      char queue_name[31];
+       struct workqueue_struct *stats_queue;
+       /* Debugfs root entry */
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-napi-prevent-overflow-of-napi_defer_hard_irqs.patch b/queue-6.10/net-napi-prevent-overflow-of-napi_defer_hard_irqs.patch
new file mode 100644 (file)
index 0000000..4161e9f
--- /dev/null
@@ -0,0 +1,125 @@
+From f5e987a9d35d39db9147ec03e22188a550dae54b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 15:34:30 +0000
+Subject: net: napi: Prevent overflow of napi_defer_hard_irqs
+
+From: Joe Damato <jdamato@fastly.com>
+
+[ Upstream commit 08062af0a52107a243f7608fd972edb54ca5b7f8 ]
+
+In commit 6f8b12d661d0 ("net: napi: add hard irqs deferral feature")
+napi_defer_irqs was added to net_device and napi_defer_irqs_count was
+added to napi_struct, both as type int.
+
+This value never goes below zero, so there is not reason for it to be a
+signed int. Change the type for both from int to u32, and add an
+overflow check to sysfs to limit the value to S32_MAX.
+
+The limit of S32_MAX was chosen because the practical limit before this
+patch was S32_MAX (anything larger was an overflow) and thus there are
+no behavioral changes introduced. If the extra bit is needed in the
+future, the limit can be raised.
+
+Before this patch:
+
+$ sudo bash -c 'echo 2147483649 > /sys/class/net/eth4/napi_defer_hard_irqs'
+$ cat /sys/class/net/eth4/napi_defer_hard_irqs
+-2147483647
+
+After this patch:
+
+$ sudo bash -c 'echo 2147483649 > /sys/class/net/eth4/napi_defer_hard_irqs'
+bash: line 0: echo: write error: Numerical result out of range
+
+Similarly, /sys/class/net/XXXXX/tx_queue_len is defined as unsigned:
+
+include/linux/netdevice.h:      unsigned int            tx_queue_len;
+
+And has an overflow check:
+
+dev_change_tx_queue_len(..., unsigned long new_len):
+
+  if (new_len != (unsigned int)new_len)
+          return -ERANGE;
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Joe Damato <jdamato@fastly.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20240904153431.307932-1-jdamato@fastly.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/networking/net_cachelines/net_device.rst | 2 +-
+ include/linux/netdevice.h                              | 4 ++--
+ net/core/net-sysfs.c                                   | 6 +++++-
+ 3 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
+index 70c4fb9d4e5ce..d68f37f5b1f82 100644
+--- a/Documentation/networking/net_cachelines/net_device.rst
++++ b/Documentation/networking/net_cachelines/net_device.rst
+@@ -98,7 +98,7 @@ unsigned_int                        num_rx_queues
+ unsigned_int                        real_num_rx_queues      -                   read_mostly         get_rps_cpu
+ struct_bpf_prog*                    xdp_prog                -                   read_mostly         netif_elide_gro()
+ unsigned_long                       gro_flush_timeout       -                   read_mostly         napi_complete_done
+-int                                 napi_defer_hard_irqs    -                   read_mostly         napi_complete_done
++u32                                 napi_defer_hard_irqs    -                   read_mostly         napi_complete_done
+ unsigned_int                        gro_max_size            -                   read_mostly         skb_gro_receive
+ unsigned_int                        gro_ipv4_max_size       -                   read_mostly         skb_gro_receive
+ rx_handler_func_t*                  rx_handler              read_mostly         -                   __netif_receive_skb_core
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 238aaed5d7236..bf3eba0d9bdca 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -354,7 +354,7 @@ struct napi_struct {
+       unsigned long           state;
+       int                     weight;
+-      int                     defer_hard_irqs_count;
++      u32                     defer_hard_irqs_count;
+       unsigned long           gro_bitmask;
+       int                     (*poll)(struct napi_struct *, int);
+ #ifdef CONFIG_NETPOLL
+@@ -2089,7 +2089,7 @@ struct net_device {
+       unsigned int            real_num_rx_queues;
+       struct netdev_rx_queue  *_rx;
+       unsigned long           gro_flush_timeout;
+-      int                     napi_defer_hard_irqs;
++      u32                     napi_defer_hard_irqs;
+       unsigned int            gro_max_size;
+       unsigned int            gro_ipv4_max_size;
+       rx_handler_func_t __rcu *rx_handler;
+diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
+index 15ad775ddd3c1..dc0c622d453e1 100644
+--- a/net/core/net-sysfs.c
++++ b/net/core/net-sysfs.c
+@@ -32,6 +32,7 @@
+ #ifdef CONFIG_SYSFS
+ static const char fmt_hex[] = "%#x\n";
+ static const char fmt_dec[] = "%d\n";
++static const char fmt_uint[] = "%u\n";
+ static const char fmt_ulong[] = "%lu\n";
+ static const char fmt_u64[] = "%llu\n";
+@@ -425,6 +426,9 @@ NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong);
+ static int change_napi_defer_hard_irqs(struct net_device *dev, unsigned long val)
+ {
++      if (val > S32_MAX)
++              return -ERANGE;
++
+       WRITE_ONCE(dev->napi_defer_hard_irqs, val);
+       return 0;
+ }
+@@ -438,7 +442,7 @@ static ssize_t napi_defer_hard_irqs_store(struct device *dev,
+       return netdev_store(dev, attr, buf, len, change_napi_defer_hard_irqs);
+ }
+-NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_dec);
++NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_uint);
+ static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t len)
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-phy-check-for-read-errors-in-siocgmiireg.patch b/queue-6.10/net-phy-check-for-read-errors-in-siocgmiireg.patch
new file mode 100644 (file)
index 0000000..f396ce5
--- /dev/null
@@ -0,0 +1,82 @@
+From 6d3f7646fb0c6b67b8d1ebe7121b6076786b4fa7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Sep 2024 19:15:36 +0200
+Subject: net: phy: Check for read errors in SIOCGMIIREG
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+
+[ Upstream commit 569bf6d481b0b823c3c9c3b8be77908fd7caf66b ]
+
+When reading registers from the PHY using the SIOCGMIIREG IOCTL any
+errors returned from either mdiobus_read() or mdiobus_c45_read() are
+ignored, and parts of the returned error is passed as the register value
+back to user-space.
+
+For example, if mdiobus_c45_read() is used with a bus that do not
+implement the read_c45() callback -EOPNOTSUPP is returned. This is
+however directly stored in mii_data->val_out and returned as the
+registers content. As val_out is a u16 the error code is truncated and
+returned as a plausible register value.
+
+Fix this by first checking the return value for errors before returning
+it as the register content.
+
+Before this patch,
+
+    # phytool read eth0/0:1/0
+    0xffa1
+
+After this change,
+
+    $ phytool read eth0/0:1/0
+    error: phy_read (-95)
+
+Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://patch.msgid.link/20240903171536.628930-1-niklas.soderlund+renesas@ragnatech.se
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/phy.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index c4236564c1cd0..8495b111a524a 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -342,14 +342,19 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
+               if (mdio_phy_id_is_c45(mii_data->phy_id)) {
+                       prtad = mdio_phy_id_prtad(mii_data->phy_id);
+                       devad = mdio_phy_id_devad(mii_data->phy_id);
+-                      mii_data->val_out = mdiobus_c45_read(
+-                              phydev->mdio.bus, prtad, devad,
+-                              mii_data->reg_num);
++                      ret = mdiobus_c45_read(phydev->mdio.bus, prtad, devad,
++                                             mii_data->reg_num);
++
+               } else {
+-                      mii_data->val_out = mdiobus_read(
+-                              phydev->mdio.bus, mii_data->phy_id,
+-                              mii_data->reg_num);
++                      ret = mdiobus_read(phydev->mdio.bus, mii_data->phy_id,
++                                         mii_data->reg_num);
+               }
++
++              if (ret < 0)
++                      return ret;
++
++              mii_data->val_out = ret;
++
+               return 0;
+       case SIOCSMIIREG:
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-sched-consistently-use-rcu_replace_pointer-in-ta.patch b/queue-6.10/net-sched-consistently-use-rcu_replace_pointer-in-ta.patch
new file mode 100644 (file)
index 0000000..62327c1
--- /dev/null
@@ -0,0 +1,42 @@
+From 241f520117cc1054317fb7f39951afd9ff80d529 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 14:54:01 +0300
+Subject: net: sched: consistently use rcu_replace_pointer() in taprio_change()
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit d5c4546062fd6f5dbce575c7ea52ad66d1968678 ]
+
+According to Vinicius (and carefully looking through the whole
+https://syzkaller.appspot.com/bug?extid=b65e0af58423fc8a73aa
+once again), txtime branch of 'taprio_change()' is not going to
+race against 'advance_sched()'. But using 'rcu_replace_pointer()'
+in the former may be a good idea as well.
+
+Suggested-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_taprio.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
+index b284a06b5a75f..847e1cc6052ec 100644
+--- a/net/sched/sch_taprio.c
++++ b/net/sched/sch_taprio.c
+@@ -1952,7 +1952,9 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
+                       goto unlock;
+               }
+-              rcu_assign_pointer(q->admin_sched, new_admin);
++              /* Not going to race against advance_sched(), but still */
++              admin = rcu_replace_pointer(q->admin_sched, new_admin,
++                                          lockdep_rtnl_is_held());
+               if (admin)
+                       call_rcu(&admin->rcu, taprio_free_sched_cb);
+       } else {
+-- 
+2.43.0
+
diff --git a/queue-6.10/net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch b/queue-6.10/net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch
new file mode 100644 (file)
index 0000000..a98fa56
--- /dev/null
@@ -0,0 +1,50 @@
+From 73a10146d82586fde1f41a92839d4046927dfb62 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Aug 2024 03:11:09 +0900
+Subject: net/xen-netback: prevent UAF in xenvif_flush_hash()
+
+From: Jeongjun Park <aha310510@gmail.com>
+
+[ Upstream commit 0fa5e94a1811d68fbffa0725efe6d4ca62c03d12 ]
+
+During the list_for_each_entry_rcu iteration call of xenvif_flush_hash,
+kfree_rcu does not exist inside the rcu read critical section, so if
+kfree_rcu is called when the rcu grace period ends during the iteration,
+UAF occurs when accessing head->next after the entry becomes free.
+
+Therefore, to solve this, you need to change it to list_for_each_entry_safe.
+
+Signed-off-by: Jeongjun Park <aha310510@gmail.com>
+Link: https://patch.msgid.link/20240822181109.2577354-1-aha310510@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/xen-netback/hash.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c
+index ff96f22648efd..45ddce35f6d2c 100644
+--- a/drivers/net/xen-netback/hash.c
++++ b/drivers/net/xen-netback/hash.c
+@@ -95,7 +95,7 @@ static u32 xenvif_new_hash(struct xenvif *vif, const u8 *data,
+ static void xenvif_flush_hash(struct xenvif *vif)
+ {
+-      struct xenvif_hash_cache_entry *entry;
++      struct xenvif_hash_cache_entry *entry, *n;
+       unsigned long flags;
+       if (xenvif_hash_cache_size == 0)
+@@ -103,8 +103,7 @@ static void xenvif_flush_hash(struct xenvif *vif)
+       spin_lock_irqsave(&vif->hash.cache.lock, flags);
+-      list_for_each_entry_rcu(entry, &vif->hash.cache.list, link,
+-                              lockdep_is_held(&vif->hash.cache.lock)) {
++      list_for_each_entry_safe(entry, n, &vif->hash.cache.list, link) {
+               list_del_rcu(&entry->link);
+               vif->hash.cache.count--;
+               kfree_rcu(entry, rcu);
+-- 
+2.43.0
+
diff --git a/queue-6.10/netdev-genl-set-extack-and-fix-error-on-napi-get.patch b/queue-6.10/netdev-genl-set-extack-and-fix-error-on-napi-get.patch
new file mode 100644 (file)
index 0000000..ef5266f
--- /dev/null
@@ -0,0 +1,64 @@
+From 8efe88df199c285fa1fb7c25ffdd492eb657d474 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 31 Aug 2024 12:17:04 +0000
+Subject: netdev-genl: Set extack and fix error on napi-get
+
+From: Joe Damato <jdamato@fastly.com>
+
+[ Upstream commit 4e3a024b437ec0aee82550cc66a0f4e1a7a88a67 ]
+
+In commit 27f91aaf49b3 ("netdev-genl: Add netlink framework functions
+for napi"), when an invalid NAPI ID is specified the return value
+-EINVAL is used and no extack is set.
+
+Change the return value to -ENOENT and set the extack.
+
+Before this commit:
+
+$ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml \
+                          --do napi-get --json='{"id": 451}'
+Netlink error: Invalid argument
+nl_len = 36 (20) nl_flags = 0x100 nl_type = 2
+       error: -22
+
+After this commit:
+
+$ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml \
+                         --do napi-get --json='{"id": 451}'
+Netlink error: No such file or directory
+nl_len = 44 (28) nl_flags = 0x300 nl_type = 2
+       error: -2
+       extack: {'bad-attr': '.id'}
+
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Joe Damato <jdamato@fastly.com>
+Link: https://patch.msgid.link/20240831121707.17562-1-jdamato@fastly.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/netdev-genl.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
+index 05f9515d2c05c..a17d7eaeb0019 100644
+--- a/net/core/netdev-genl.c
++++ b/net/core/netdev-genl.c
+@@ -216,10 +216,12 @@ int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
+       rtnl_lock();
+       napi = napi_by_id(napi_id);
+-      if (napi)
++      if (napi) {
+               err = netdev_nl_napi_fill_one(rsp, napi, info);
+-      else
+-              err = -EINVAL;
++      } else {
++              NL_SET_BAD_ATTR(info->extack, info->attrs[NETDEV_A_NAPI_ID]);
++              err = -ENOENT;
++      }
+       rtnl_unlock();
+-- 
+2.43.0
+
diff --git a/queue-6.10/netfs-cancel-dirty-folios-that-have-no-storage-desti.patch b/queue-6.10/netfs-cancel-dirty-folios-that-have-no-storage-desti.patch
new file mode 100644 (file)
index 0000000..ac3dc57
--- /dev/null
@@ -0,0 +1,80 @@
+From 7443e050d5fa286109f59516636837d386852d99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 12:23:11 +0100
+Subject: netfs: Cancel dirty folios that have no storage destination
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit 8f246b7c0a1be0882374f2ff831a61f0dbe77678 ]
+
+Kafs wants to be able to cache the contents of directories (and symlinks),
+but whilst these are downloaded from the server with the FS.FetchData RPC
+op and similar, the same as for regular files, they can't be updated by
+FS.StoreData, but rather have special operations (FS.MakeDir, etc.).
+
+Now, rather than redownloading a directory's content after each change made
+to that directory, kafs modifies the local blob.  This blob can be saved
+out to the cache, and since it's using netfslib, kafs just marks the folios
+dirty and lets ->writepages() on the directory take care of it, as for an
+regular file.
+
+This is fine as long as there's a cache as although the upload stream is
+disabled, there's a cache stream to drive the procedure.  But if the cache
+goes away in the meantime, suddenly there's no way do any writes and the
+code gets confused, complains "R=%x: No submit" to dmesg and leaves the
+dirty folio hanging.
+
+Fix this by just cancelling the store of the folio if neither stream is
+active.  (If there's no cache at the time of dirtying, we should just not
+mark the folio dirty).
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Jeff Layton <jlayton@kernel.org>
+cc: netfs@lists.linux.dev
+cc: linux-fsdevel@vger.kernel.org
+Link: https://lore.kernel.org/r/20240814203850.2240469-23-dhowells@redhat.com/ # v2
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/netfs/write_issue.c       | 6 +++++-
+ include/trace/events/netfs.h | 1 +
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
+index 32bc88bee5d18..3c7eb43a2ec69 100644
+--- a/fs/netfs/write_issue.c
++++ b/fs/netfs/write_issue.c
+@@ -408,13 +408,17 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
+       folio_unlock(folio);
+       if (fgroup == NETFS_FOLIO_COPY_TO_CACHE) {
+-              if (!fscache_resources_valid(&wreq->cache_resources)) {
++              if (!cache->avail) {
+                       trace_netfs_folio(folio, netfs_folio_trace_cancel_copy);
+                       netfs_issue_write(wreq, upload);
+                       netfs_folio_written_back(folio);
+                       return 0;
+               }
+               trace_netfs_folio(folio, netfs_folio_trace_store_copy);
++      } else if (!upload->avail && !cache->avail) {
++              trace_netfs_folio(folio, netfs_folio_trace_cancel_store);
++              netfs_folio_written_back(folio);
++              return 0;
+       } else if (!upload->construct) {
+               trace_netfs_folio(folio, netfs_folio_trace_store);
+       } else {
+diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
+index 24ec3434d32ee..102696abe8c9e 100644
+--- a/include/trace/events/netfs.h
++++ b/include/trace/events/netfs.h
+@@ -140,6 +140,7 @@
+       EM(netfs_streaming_cont_filled_page,    "mod-streamw-f+") \
+       /* The rest are for writeback */                        \
+       EM(netfs_folio_trace_cancel_copy,       "cancel-copy")  \
++      EM(netfs_folio_trace_cancel_store,      "cancel-store") \
+       EM(netfs_folio_trace_clear,             "clear")        \
+       EM(netfs_folio_trace_clear_cc,          "clear-cc")     \
+       EM(netfs_folio_trace_clear_g,           "clear-g")      \
+-- 
+2.43.0
+
diff --git a/queue-6.10/netpoll-ensure-clean-state-on-setup-failures.patch b/queue-6.10/netpoll-ensure-clean-state-on-setup-failures.patch
new file mode 100644 (file)
index 0000000..b1a7692
--- /dev/null
@@ -0,0 +1,106 @@
+From cc32c0f92768aae1dc672953165f1d8c661df419 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 04:10:47 -0700
+Subject: netpoll: Ensure clean state on setup failures
+
+From: Breno Leitao <leitao@debian.org>
+
+[ Upstream commit ae5a0456e0b4cfd7e61619e55251ffdf1bc7adfb ]
+
+Modify netpoll_setup() and __netpoll_setup() to ensure that the netpoll
+structure (np) is left in a clean state if setup fails for any reason.
+This prevents carrying over misconfigured fields in case of partial
+setup success.
+
+Key changes:
+- np->dev is now set only after successful setup, ensuring it's always
+  NULL if netpoll is not configured or if netpoll_setup() fails.
+- np->local_ip is zeroed if netpoll setup doesn't complete successfully.
+- Added DEBUG_NET_WARN_ON_ONCE() checks to catch unexpected states.
+- Reordered some operations in __netpoll_setup() for better logical flow.
+
+These changes improve the reliability of netpoll configuration, since it
+assures that the structure is fully initialized or totally unset.
+
+Suggested-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Breno Leitao <leitao@debian.org>
+Link: https://patch.msgid.link/20240822111051.179850-2-leitao@debian.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/netpoll.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/net/core/netpoll.c b/net/core/netpoll.c
+index 55bcacf67df3b..e082139004093 100644
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -626,12 +626,9 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+       const struct net_device_ops *ops;
+       int err;
+-      np->dev = ndev;
+-      strscpy(np->dev_name, ndev->name, IFNAMSIZ);
+-
+       if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
+               np_err(np, "%s doesn't support polling, aborting\n",
+-                     np->dev_name);
++                     ndev->name);
+               err = -ENOTSUPP;
+               goto out;
+       }
+@@ -649,7 +646,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+               refcount_set(&npinfo->refcnt, 1);
+-              ops = np->dev->netdev_ops;
++              ops = ndev->netdev_ops;
+               if (ops->ndo_netpoll_setup) {
+                       err = ops->ndo_netpoll_setup(ndev, npinfo);
+                       if (err)
+@@ -660,6 +657,8 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+               refcount_inc(&npinfo->refcnt);
+       }
++      np->dev = ndev;
++      strscpy(np->dev_name, ndev->name, IFNAMSIZ);
+       npinfo->netpoll = np;
+       /* last thing to do is link it to the net device structure */
+@@ -677,6 +676,7 @@ EXPORT_SYMBOL_GPL(__netpoll_setup);
+ int netpoll_setup(struct netpoll *np)
+ {
+       struct net_device *ndev = NULL;
++      bool ip_overwritten = false;
+       struct in_device *in_dev;
+       int err;
+@@ -741,6 +741,7 @@ int netpoll_setup(struct netpoll *np)
+                       }
+                       np->local_ip.ip = ifa->ifa_local;
++                      ip_overwritten = true;
+                       np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+               } else {
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -757,6 +758,7 @@ int netpoll_setup(struct netpoll *np)
+                                           !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
+                                               continue;
+                                       np->local_ip.in6 = ifp->addr;
++                                      ip_overwritten = true;
+                                       err = 0;
+                                       break;
+                               }
+@@ -787,6 +789,9 @@ int netpoll_setup(struct netpoll *np)
+       return 0;
+ put:
++      DEBUG_NET_WARN_ON_ONCE(np->dev);
++      if (ip_overwritten)
++              memset(&np->local_ip, 0, sizeof(np->local_ip));
+       netdev_put(ndev, &np->dev_tracker);
+ unlock:
+       rtnl_unlock();
+-- 
+2.43.0
+
diff --git a/queue-6.10/nfp-use-irqf_no_autoen-flag-in-request_irq.patch b/queue-6.10/nfp-use-irqf_no_autoen-flag-in-request_irq.patch
new file mode 100644 (file)
index 0000000..05ff11c
--- /dev/null
@@ -0,0 +1,46 @@
+From 6ce22b4ecebbfcb604c360865aba9eb1dac6919c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 17:44:45 +0800
+Subject: nfp: Use IRQF_NO_AUTOEN flag in request_irq()
+
+From: Jinjie Ruan <ruanjinjie@huawei.com>
+
+[ Upstream commit daaba19d357f0900b303a530ced96c78086267ea ]
+
+disable_irq() after request_irq() still has a time gap in which
+interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will
+disable IRQ auto-enable when request IRQ.
+
+Reviewed-by: Louis Peens <louis.peens@corigine.com>
+Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
+Link: https://patch.msgid.link/20240911094445.1922476-4-ruanjinjie@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+index 182ba0a8b095b..6e0929af0f725 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+@@ -821,14 +821,13 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
+       snprintf(r_vec->name, sizeof(r_vec->name),
+                "%s-rxtx-%d", nfp_net_name(nn), idx);
+-      err = request_irq(r_vec->irq_vector, r_vec->handler, 0, r_vec->name,
+-                        r_vec);
++      err = request_irq(r_vec->irq_vector, r_vec->handler, IRQF_NO_AUTOEN,
++                        r_vec->name, r_vec);
+       if (err) {
+               nfp_net_napi_del(&nn->dp, r_vec);
+               nn_err(nn, "Error requesting IRQ %d\n", r_vec->irq_vector);
+               return err;
+       }
+-      disable_irq(r_vec->irq_vector);
+       irq_set_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask);
+-- 
+2.43.0
+
diff --git a/queue-6.10/nvme-keyring-restrict-match-length-for-version-1-ide.patch b/queue-6.10/nvme-keyring-restrict-match-length-for-version-1-ide.patch
new file mode 100644 (file)
index 0000000..49dd4b4
--- /dev/null
@@ -0,0 +1,133 @@
+From e4cb0b82c255d54cf95eebc201f58f3cf282606c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 14:02:18 +0200
+Subject: nvme-keyring: restrict match length for version '1' identifiers
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 79559c75332458985ab8a21f11b08bf7c9b833b0 ]
+
+TP8018 introduced a new TLS PSK identifier version (version 1), which appended
+a PSK hash value to the existing identifier (cf NVMe TCP specification v1.1,
+section 3.6.1.3 'TLS PSK and PSK Identity Derivation').
+An original (version 0) identifier has the form:
+
+NVMe0<type><hmac> <hostnqn> <subsysnqn>
+
+and a version 1 identifier has the form:
+
+NVMe1<type><hmac> <hostnqn> <subsysnqn> <hash>
+
+This patch modifies the lookup algorthm to compare only the first part
+of the identifier (excluding the hash value) to handle both version 0 and
+version 1 identifiers.
+And the spec declares 'version 0' identifiers obsolete, so the lookup
+algorithm is modified to prever v1 identifiers.
+
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/common/keyring.c | 36 +++++++++++++++++++++++++----------
+ 1 file changed, 26 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/nvme/common/keyring.c b/drivers/nvme/common/keyring.c
+index 6f7e7a8fa5ae4..05e89307c8aa3 100644
+--- a/drivers/nvme/common/keyring.c
++++ b/drivers/nvme/common/keyring.c
+@@ -36,14 +36,12 @@ static bool nvme_tls_psk_match(const struct key *key,
+               pr_debug("%s: no key description\n", __func__);
+               return false;
+       }
+-      match_len = strlen(key->description);
+-      pr_debug("%s: id %s len %zd\n", __func__, key->description, match_len);
+-
+       if (!match_data->raw_data) {
+               pr_debug("%s: no match data\n", __func__);
+               return false;
+       }
+       match_id = match_data->raw_data;
++      match_len = strlen(match_id);
+       pr_debug("%s: match '%s' '%s' len %zd\n",
+                __func__, match_id, key->description, match_len);
+       return !memcmp(key->description, match_id, match_len);
+@@ -71,7 +69,7 @@ static struct key_type nvme_tls_psk_key_type = {
+ static struct key *nvme_tls_psk_lookup(struct key *keyring,
+               const char *hostnqn, const char *subnqn,
+-              int hmac, bool generated)
++              u8 hmac, u8 psk_ver, bool generated)
+ {
+       char *identity;
+       size_t identity_len = (NVMF_NQN_SIZE) * 2 + 11;
+@@ -82,8 +80,8 @@ static struct key *nvme_tls_psk_lookup(struct key *keyring,
+       if (!identity)
+               return ERR_PTR(-ENOMEM);
+-      snprintf(identity, identity_len, "NVMe0%c%02d %s %s",
+-               generated ? 'G' : 'R', hmac, hostnqn, subnqn);
++      snprintf(identity, identity_len, "NVMe%u%c%02u %s %s",
++               psk_ver, generated ? 'G' : 'R', hmac, hostnqn, subnqn);
+       if (!keyring)
+               keyring = nvme_keyring;
+@@ -107,21 +105,38 @@ static struct key *nvme_tls_psk_lookup(struct key *keyring,
+ /*
+  * NVMe PSK priority list
+  *
+- * 'Retained' PSKs (ie 'generated == false')
+- * should be preferred to 'generated' PSKs,
+- * and SHA-384 should be preferred to SHA-256.
++ * 'Retained' PSKs (ie 'generated == false') should be preferred to 'generated'
++ * PSKs, PSKs with hash (psk_ver 1) should be preferred to PSKs without hash
++ * (psk_ver 0), and SHA-384 should be preferred to SHA-256.
+  */
+ static struct nvme_tls_psk_priority_list {
+       bool generated;
++      u8 psk_ver;
+       enum nvme_tcp_tls_cipher cipher;
+ } nvme_tls_psk_prio[] = {
+       { .generated = false,
++        .psk_ver = 1,
++        .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
++      { .generated = false,
++        .psk_ver = 1,
++        .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
++      { .generated = false,
++        .psk_ver = 0,
+         .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
+       { .generated = false,
++        .psk_ver = 0,
++        .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
++      { .generated = true,
++        .psk_ver = 1,
++        .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
++      { .generated = true,
++        .psk_ver = 1,
+         .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
+       { .generated = true,
++        .psk_ver = 0,
+         .cipher = NVME_TCP_TLS_CIPHER_SHA384, },
+       { .generated = true,
++        .psk_ver = 0,
+         .cipher = NVME_TCP_TLS_CIPHER_SHA256, },
+ };
+@@ -137,10 +152,11 @@ key_serial_t nvme_tls_psk_default(struct key *keyring,
+       for (prio = 0; prio < ARRAY_SIZE(nvme_tls_psk_prio); prio++) {
+               bool generated = nvme_tls_psk_prio[prio].generated;
++              u8 ver = nvme_tls_psk_prio[prio].psk_ver;
+               enum nvme_tcp_tls_cipher cipher = nvme_tls_psk_prio[prio].cipher;
+               tls_key = nvme_tls_psk_lookup(keyring, hostnqn, subnqn,
+-                                            cipher, generated);
++                                            cipher, ver, generated);
+               if (!IS_ERR(tls_key)) {
+                       tls_key_id = tls_key->serial;
+                       key_put(tls_key);
+-- 
+2.43.0
+
diff --git a/queue-6.10/nvme-tcp-check-for-invalidated-or-revoked-key.patch b/queue-6.10/nvme-tcp-check-for-invalidated-or-revoked-key.patch
new file mode 100644 (file)
index 0000000..70c0860
--- /dev/null
@@ -0,0 +1,122 @@
+From 2f4c1f49f5699a783b73d03d94f0c4c473890e68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 14:02:20 +0200
+Subject: nvme-tcp: check for invalidated or revoked key
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 5bc46b49c828a6dfaab80b71ecb63fe76a1096d2 ]
+
+key_lookup() will always return a key, even if that key is revoked
+or invalidated. So check for invalid keys before continuing.
+
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/common/keyring.c | 22 ++++++++++++++++++++++
+ drivers/nvme/host/Kconfig     |  1 +
+ drivers/nvme/host/fabrics.c   |  2 +-
+ drivers/nvme/host/tcp.c       |  2 +-
+ include/linux/nvme-keyring.h  |  6 +++++-
+ 5 files changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/nvme/common/keyring.c b/drivers/nvme/common/keyring.c
+index 05e89307c8aa3..ed5167f942d89 100644
+--- a/drivers/nvme/common/keyring.c
++++ b/drivers/nvme/common/keyring.c
+@@ -20,6 +20,28 @@ key_serial_t nvme_keyring_id(void)
+ }
+ EXPORT_SYMBOL_GPL(nvme_keyring_id);
++static bool nvme_tls_psk_revoked(struct key *psk)
++{
++      return test_bit(KEY_FLAG_REVOKED, &psk->flags) ||
++              test_bit(KEY_FLAG_INVALIDATED, &psk->flags);
++}
++
++struct key *nvme_tls_key_lookup(key_serial_t key_id)
++{
++      struct key *key = key_lookup(key_id);
++
++      if (IS_ERR(key)) {
++              pr_err("key id %08x not found\n", key_id);
++              return key;
++      }
++      if (nvme_tls_psk_revoked(key)) {
++              pr_err("key id %08x revoked\n", key_id);
++              return ERR_PTR(-EKEYREVOKED);
++      }
++      return key;
++}
++EXPORT_SYMBOL_GPL(nvme_tls_key_lookup);
++
+ static void nvme_tls_psk_describe(const struct key *key, struct seq_file *m)
+ {
+       seq_puts(m, key->description);
+diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
+index b309c8be720f4..854eb26ac3db9 100644
+--- a/drivers/nvme/host/Kconfig
++++ b/drivers/nvme/host/Kconfig
+@@ -110,6 +110,7 @@ config NVME_HOST_AUTH
+       bool "NVMe over Fabrics In-Band Authentication in host side"
+       depends on NVME_CORE
+       select NVME_AUTH
++      select NVME_KEYRING if NVME_TCP_TLS
+       help
+         This provides support for NVMe over Fabrics In-Band Authentication in
+         host side.
+diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
+index b5a4b5fd573e0..3e3db6a6524e0 100644
+--- a/drivers/nvme/host/fabrics.c
++++ b/drivers/nvme/host/fabrics.c
+@@ -650,7 +650,7 @@ static struct key *nvmf_parse_key(int key_id)
+               return ERR_PTR(-EINVAL);
+       }
+-      key = key_lookup(key_id);
++      key = nvme_tls_key_lookup(key_id);
+       if (IS_ERR(key))
+               pr_err("key id %08x not found\n", key_id);
+       else
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index f551609691807..8c79af3ed1f23 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -1596,7 +1596,7 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid)
+               goto out_complete;
+       }
+-      tls_key = key_lookup(pskid);
++      tls_key = nvme_tls_key_lookup(pskid);
+       if (IS_ERR(tls_key)) {
+               dev_warn(ctrl->ctrl.device, "queue %d: Invalid key %x\n",
+                        qid, pskid);
+diff --git a/include/linux/nvme-keyring.h b/include/linux/nvme-keyring.h
+index e10333d78dbbe..19d2b256180fd 100644
+--- a/include/linux/nvme-keyring.h
++++ b/include/linux/nvme-keyring.h
+@@ -12,7 +12,7 @@ key_serial_t nvme_tls_psk_default(struct key *keyring,
+               const char *hostnqn, const char *subnqn);
+ key_serial_t nvme_keyring_id(void);
+-
++struct key *nvme_tls_key_lookup(key_serial_t key_id);
+ #else
+ static inline key_serial_t nvme_tls_psk_default(struct key *keyring,
+@@ -24,5 +24,9 @@ static inline key_serial_t nvme_keyring_id(void)
+ {
+       return 0;
+ }
++static inline struct key *nvme_tls_key_lookup(key_serial_t key_id)
++{
++      return ERR_PTR(-ENOTSUPP);
++}
+ #endif /* !CONFIG_NVME_KEYRING */
+ #endif /* _NVME_KEYRING_H */
+-- 
+2.43.0
+
diff --git a/queue-6.10/nvme-tcp-sanitize-tls-key-handling.patch b/queue-6.10/nvme-tcp-sanitize-tls-key-handling.patch
new file mode 100644 (file)
index 0000000..e15605e
--- /dev/null
@@ -0,0 +1,220 @@
+From 3b741c3360d973144c6de7f0a0240dc237c6c5fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jul 2024 14:02:19 +0200
+Subject: nvme-tcp: sanitize TLS key handling
+
+From: Hannes Reinecke <hare@kernel.org>
+
+[ Upstream commit 363895767fbfa05891b0b4d9e06ebde7a10c6a07 ]
+
+There is a difference between TLS configured (ie the user has
+provisioned/requested a key) and TLS enabled (ie the connection
+is encrypted with TLS). This becomes important for secure concatenation,
+where the initial authentication is run on an unencrypted connection
+(ie with TLS configured, but not enabled), and then the queue is reset to
+run over TLS (ie TLS configured _and_ enabled).
+So to differentiate between those two states store the generated
+key in opts->tls_key (as we're using the same TLS key for all queues),
+the key serial of the resulting TLS handshake in ctrl->tls_pskid
+(to signal that TLS on the admin queue is enabled), and a simple
+flag for the queues to indicated that TLS has been enabled.
+
+Signed-off-by: Hannes Reinecke <hare@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/nvme/host/core.c  |  1 -
+ drivers/nvme/host/nvme.h  |  2 +-
+ drivers/nvme/host/sysfs.c |  4 +--
+ drivers/nvme/host/tcp.c   | 53 +++++++++++++++++++++++++++++----------
+ 4 files changed, 43 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 5569cf4183b2a..415ede9886c12 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -4587,7 +4587,6 @@ static void nvme_free_ctrl(struct device *dev)
+       if (!subsys || ctrl->instance != subsys->instance)
+               ida_free(&nvme_instance_ida, ctrl->instance);
+-      key_put(ctrl->tls_key);
+       nvme_free_cels(ctrl);
+       nvme_mpath_uninit(ctrl);
+       cleanup_srcu_struct(&ctrl->srcu);
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index ff1769172778b..cde1cb906dbf2 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -375,7 +375,7 @@ struct nvme_ctrl {
+       struct nvme_dhchap_key *ctrl_key;
+       u16 transaction;
+ #endif
+-      struct key *tls_key;
++      key_serial_t tls_pskid;
+       /* Power saving configuration */
+       u64 ps_max_latency_us;
+diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
+index 3c55f7edd1819..5b1dee8a66ef8 100644
+--- a/drivers/nvme/host/sysfs.c
++++ b/drivers/nvme/host/sysfs.c
+@@ -671,9 +671,9 @@ static ssize_t tls_key_show(struct device *dev,
+ {
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+-      if (!ctrl->tls_key)
++      if (!ctrl->tls_pskid)
+               return 0;
+-      return sysfs_emit(buf, "%08x", key_serial(ctrl->tls_key));
++      return sysfs_emit(buf, "%08x", ctrl->tls_pskid);
+ }
+ static DEVICE_ATTR_RO(tls_key);
+ #endif
+diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
+index 8b5e4327fe83b..f551609691807 100644
+--- a/drivers/nvme/host/tcp.c
++++ b/drivers/nvme/host/tcp.c
+@@ -165,6 +165,7 @@ struct nvme_tcp_queue {
+       bool                    hdr_digest;
+       bool                    data_digest;
++      bool                    tls_enabled;
+       struct ahash_request    *rcv_hash;
+       struct ahash_request    *snd_hash;
+       __le32                  exp_ddgst;
+@@ -213,7 +214,21 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
+       return queue - queue->ctrl->queues;
+ }
+-static inline bool nvme_tcp_tls(struct nvme_ctrl *ctrl)
++/*
++ * Check if the queue is TLS encrypted
++ */
++static inline bool nvme_tcp_queue_tls(struct nvme_tcp_queue *queue)
++{
++      if (!IS_ENABLED(CONFIG_NVME_TCP_TLS))
++              return 0;
++
++      return queue->tls_enabled;
++}
++
++/*
++ * Check if TLS is configured for the controller.
++ */
++static inline bool nvme_tcp_tls_configured(struct nvme_ctrl *ctrl)
+ {
+       if (!IS_ENABLED(CONFIG_NVME_TCP_TLS))
+               return 0;
+@@ -368,7 +383,7 @@ static inline bool nvme_tcp_queue_has_pending(struct nvme_tcp_queue *queue)
+ static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
+ {
+-      return !nvme_tcp_tls(&queue->ctrl->ctrl) &&
++      return !nvme_tcp_queue_tls(queue) &&
+               nvme_tcp_queue_has_pending(queue);
+ }
+@@ -1427,7 +1442,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
+       memset(&msg, 0, sizeof(msg));
+       iov.iov_base = icresp;
+       iov.iov_len = sizeof(*icresp);
+-      if (nvme_tcp_tls(&queue->ctrl->ctrl)) {
++      if (nvme_tcp_queue_tls(queue)) {
+               msg.msg_control = cbuf;
+               msg.msg_controllen = sizeof(cbuf);
+       }
+@@ -1439,7 +1454,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
+               goto free_icresp;
+       }
+       ret = -ENOTCONN;
+-      if (nvme_tcp_tls(&queue->ctrl->ctrl)) {
++      if (nvme_tcp_queue_tls(queue)) {
+               ctype = tls_get_record_type(queue->sock->sk,
+                                           (struct cmsghdr *)cbuf);
+               if (ctype != TLS_RECORD_TYPE_DATA) {
+@@ -1587,7 +1602,10 @@ static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid)
+                        qid, pskid);
+               queue->tls_err = -ENOKEY;
+       } else {
+-              ctrl->ctrl.tls_key = tls_key;
++              queue->tls_enabled = true;
++              if (qid == 0)
++                      ctrl->ctrl.tls_pskid = key_serial(tls_key);
++              key_put(tls_key);
+               queue->tls_err = 0;
+       }
+@@ -1768,7 +1786,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
+       }
+       /* If PSKs are configured try to start TLS */
+-      if (IS_ENABLED(CONFIG_NVME_TCP_TLS) && pskid) {
++      if (nvme_tcp_tls_configured(nctrl) && pskid) {
+               ret = nvme_tcp_start_tls(nctrl, queue, pskid);
+               if (ret)
+                       goto err_init_connect;
+@@ -1829,6 +1847,8 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
+       mutex_lock(&queue->queue_lock);
+       if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
+               __nvme_tcp_stop_queue(queue);
++      /* Stopping the queue will disable TLS */
++      queue->tls_enabled = false;
+       mutex_unlock(&queue->queue_lock);
+ }
+@@ -1925,16 +1945,17 @@ static int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl)
+       int ret;
+       key_serial_t pskid = 0;
+-      if (nvme_tcp_tls(ctrl)) {
++      if (nvme_tcp_tls_configured(ctrl)) {
+               if (ctrl->opts->tls_key)
+                       pskid = key_serial(ctrl->opts->tls_key);
+-              else
++              else {
+                       pskid = nvme_tls_psk_default(ctrl->opts->keyring,
+                                                     ctrl->opts->host->nqn,
+                                                     ctrl->opts->subsysnqn);
+-              if (!pskid) {
+-                      dev_err(ctrl->device, "no valid PSK found\n");
+-                      return -ENOKEY;
++                      if (!pskid) {
++                              dev_err(ctrl->device, "no valid PSK found\n");
++                              return -ENOKEY;
++                      }
+               }
+       }
+@@ -1957,13 +1978,14 @@ static int __nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl)
+ {
+       int i, ret;
+-      if (nvme_tcp_tls(ctrl) && !ctrl->tls_key) {
++      if (nvme_tcp_tls_configured(ctrl) && !ctrl->tls_pskid) {
+               dev_err(ctrl->device, "no PSK negotiated\n");
+               return -ENOKEY;
+       }
++
+       for (i = 1; i < ctrl->queue_count; i++) {
+               ret = nvme_tcp_alloc_queue(ctrl, i,
+-                              key_serial(ctrl->tls_key));
++                              ctrl->tls_pskid);
+               if (ret)
+                       goto out_free_queues;
+       }
+@@ -2144,6 +2166,11 @@ static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
+       if (remove)
+               nvme_unquiesce_admin_queue(ctrl);
+       nvme_tcp_destroy_admin_queue(ctrl, remove);
++      if (ctrl->tls_pskid) {
++              dev_dbg(ctrl->device, "Wipe negotiated TLS_PSK %08x\n",
++                      ctrl->tls_pskid);
++              ctrl->tls_pskid = 0;
++      }
+ }
+ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
+-- 
+2.43.0
+
diff --git a/queue-6.10/of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch b/queue-6.10/of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch
new file mode 100644 (file)
index 0000000..5e00202
--- /dev/null
@@ -0,0 +1,39 @@
+From dc34b39511bf9d69041a12cb90ea16c63f221b0d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Aug 2024 14:16:53 +0200
+Subject: of/irq: Refer to actual buffer size in of_irq_parse_one()
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit 39ab331ab5d377a18fbf5a0e0b228205edfcc7f4 ]
+
+Replace two open-coded calculations of the buffer size by invocations of
+sizeof() on the buffer itself, to make sure the code will always use the
+actual buffer size.
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://lore.kernel.org/r/817c0b9626fd30790fc488c472a3398324cfcc0c.1724156125.git.geert+renesas@glider.be
+Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/of/irq.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/of/irq.c b/drivers/of/irq.c
+index 8fd63100ba8f0..d67b69cb84bfe 100644
+--- a/drivers/of/irq.c
++++ b/drivers/of/irq.c
+@@ -357,8 +357,8 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
+       addr = of_get_property(device, "reg", &addr_len);
+       /* Prevent out-of-bounds read in case of longer interrupt parent address size */
+-      if (addr_len > (3 * sizeof(__be32)))
+-              addr_len = 3 * sizeof(__be32);
++      if (addr_len > sizeof(addr_buf))
++              addr_len = sizeof(addr_buf);
+       if (addr)
+               memcpy(addr_buf, addr, addr_len);
+-- 
+2.43.0
+
diff --git a/queue-6.10/ovl-fsync-after-metadata-copy-up.patch b/queue-6.10/ovl-fsync-after-metadata-copy-up.patch
new file mode 100644 (file)
index 0000000..81920c5
--- /dev/null
@@ -0,0 +1,131 @@
+From b4b715725669e2f5059f875f877465a0f8239aa0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 17:51:08 +0200
+Subject: ovl: fsync after metadata copy-up
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+[ Upstream commit 7d6899fb69d25e1bc6f4700b7c1d92e6b608593d ]
+
+For upper filesystems which do not use strict ordering of persisting
+metadata changes (e.g. ubifs), when overlayfs file is modified for
+the first time, copy up will create a copy of the lower file and
+its parent directories in the upper layer. Permission lost of the
+new upper parent directory was observed during power-cut stress test.
+
+Fix by moving the fsync call to after metadata copy to make sure that the
+metadata copied up directory and files persists to disk before renaming
+from tmp to final destination.
+
+With metacopy enabled, this change will hurt performance of workloads
+such as chown -R, so we keep the legacy behavior of fsync only on copyup
+of data.
+
+Link: https://lore.kernel.org/linux-unionfs/CAOQ4uxj-pOvmw1-uXR3qVdqtLjSkwcR9nVKcNU_vC10Zyf2miQ@mail.gmail.com/
+Reported-and-tested-by: Fei Lv <feilv@asrmicro.com>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/overlayfs/copy_up.c | 43 ++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 39 insertions(+), 4 deletions(-)
+
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index a5ef2005a2cc5..051a802893a18 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -243,8 +243,24 @@ static int ovl_verify_area(loff_t pos, loff_t pos2, loff_t len, loff_t totlen)
+       return 0;
+ }
++static int ovl_sync_file(struct path *path)
++{
++      struct file *new_file;
++      int err;
++
++      new_file = ovl_path_open(path, O_LARGEFILE | O_RDONLY);
++      if (IS_ERR(new_file))
++              return PTR_ERR(new_file);
++
++      err = vfs_fsync(new_file, 0);
++      fput(new_file);
++
++      return err;
++}
++
+ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
+-                          struct file *new_file, loff_t len)
++                          struct file *new_file, loff_t len,
++                          bool datasync)
+ {
+       struct path datapath;
+       struct file *old_file;
+@@ -342,7 +358,8 @@ static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
+               len -= bytes;
+       }
+-      if (!error && ovl_should_sync(ofs))
++      /* call fsync once, either now or later along with metadata */
++      if (!error && ovl_should_sync(ofs) && datasync)
+               error = vfs_fsync(new_file, 0);
+ out_fput:
+       fput(old_file);
+@@ -574,6 +591,7 @@ struct ovl_copy_up_ctx {
+       bool indexed;
+       bool metacopy;
+       bool metacopy_digest;
++      bool metadata_fsync;
+ };
+ static int ovl_link_up(struct ovl_copy_up_ctx *c)
+@@ -634,7 +652,8 @@ static int ovl_copy_up_data(struct ovl_copy_up_ctx *c, const struct path *temp)
+       if (IS_ERR(new_file))
+               return PTR_ERR(new_file);
+-      err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size);
++      err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size,
++                             !c->metadata_fsync);
+       fput(new_file);
+       return err;
+@@ -701,6 +720,10 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
+               err = ovl_set_attr(ofs, temp, &c->stat);
+       inode_unlock(temp->d_inode);
++      /* fsync metadata before moving it into upper dir */
++      if (!err && ovl_should_sync(ofs) && c->metadata_fsync)
++              err = ovl_sync_file(&upperpath);
++
+       return err;
+ }
+@@ -860,7 +883,8 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+       temp = tmpfile->f_path.dentry;
+       if (!c->metacopy && c->stat.size) {
+-              err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
++              err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size,
++                                     !c->metadata_fsync);
+               if (err)
+                       goto out_fput;
+       }
+@@ -1135,6 +1159,17 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
+           !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
+               return -EOVERFLOW;
++      /*
++       * With metacopy disabled, we fsync after final metadata copyup, for
++       * both regular files and directories to get atomic copyup semantics
++       * on filesystems that do not use strict metadata ordering (e.g. ubifs).
++       *
++       * With metacopy enabled we want to avoid fsync on all meta copyup
++       * that will hurt performance of workloads such as chown -R, so we
++       * only fsync on data copyup as legacy behavior.
++       */
++      ctx.metadata_fsync = !OVL_FS(dentry->d_sb)->config.metacopy &&
++                           (S_ISREG(ctx.stat.mode) || S_ISDIR(ctx.stat.mode));
+       ctx.metacopy = ovl_need_meta_copy_up(dentry, ctx.stat.mode, flags);
+       if (parent) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/perf-fix-event_function_call-locking.patch b/queue-6.10/perf-fix-event_function_call-locking.patch
new file mode 100644 (file)
index 0000000..27fa444
--- /dev/null
@@ -0,0 +1,63 @@
+From 9708913b983d7d207e6e650cb94aafdb2e269b7a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 13:29:27 +0200
+Subject: perf: Fix event_function_call() locking
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 558abc7e3f895049faa46b08656be4c60dc6e9fd ]
+
+All the event_function/@func call context already uses perf_ctx_lock()
+except for the !ctx->is_active case. Make it all consistent.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
+Reviewed-by: Namhyung Kim <namhyung@kernel.org>
+Link: https://lore.kernel.org/r/20240807115550.138301094@infradead.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 081d9692ce747..e18a07de9920a 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -263,6 +263,7 @@ static int event_function(void *info)
+ static void event_function_call(struct perf_event *event, event_f func, void *data)
+ {
+       struct perf_event_context *ctx = event->ctx;
++      struct perf_cpu_context *cpuctx = this_cpu_ptr(&perf_cpu_context);
+       struct task_struct *task = READ_ONCE(ctx->task); /* verified in event_function */
+       struct event_function_struct efs = {
+               .event = event,
+@@ -291,22 +292,22 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
+       if (!task_function_call(task, event_function, &efs))
+               return;
+-      raw_spin_lock_irq(&ctx->lock);
++      perf_ctx_lock(cpuctx, ctx);
+       /*
+        * Reload the task pointer, it might have been changed by
+        * a concurrent perf_event_context_sched_out().
+        */
+       task = ctx->task;
+       if (task == TASK_TOMBSTONE) {
+-              raw_spin_unlock_irq(&ctx->lock);
++              perf_ctx_unlock(cpuctx, ctx);
+               return;
+       }
+       if (ctx->is_active) {
+-              raw_spin_unlock_irq(&ctx->lock);
++              perf_ctx_unlock(cpuctx, ctx);
+               goto again;
+       }
+       func(event, NULL, ctx, data);
+-      raw_spin_unlock_irq(&ctx->lock);
++      perf_ctx_unlock(cpuctx, ctx);
+ }
+ /*
+-- 
+2.43.0
+
diff --git a/queue-6.10/perf-x86-avoid-missing-caller-address-in-stack-trace.patch b/queue-6.10/perf-x86-avoid-missing-caller-address-in-stack-trace.patch
new file mode 100644 (file)
index 0000000..5e03a0f
--- /dev/null
@@ -0,0 +1,197 @@
+From a8b6632c02c45eb65a8fa2aab392b485c373c415 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 10:52:23 -0700
+Subject: perf,x86: avoid missing caller address in stack traces captured in
+ uprobe
+
+From: Andrii Nakryiko <andrii@kernel.org>
+
+[ Upstream commit cfa7f3d2c526c224a6271cc78a4a27a0de06f4f0 ]
+
+When tracing user functions with uprobe functionality, it's common to
+install the probe (e.g., a BPF program) at the first instruction of the
+function. This is often going to be `push %rbp` instruction in function
+preamble, which means that within that function frame pointer hasn't
+been established yet. This leads to consistently missing an actual
+caller of the traced function, because perf_callchain_user() only
+records current IP (capturing traced function) and then following frame
+pointer chain (which would be caller's frame, containing the address of
+caller's caller).
+
+So when we have target_1 -> target_2 -> target_3 call chain and we are
+tracing an entry to target_3, captured stack trace will report
+target_1 -> target_3 call chain, which is wrong and confusing.
+
+This patch proposes a x86-64-specific heuristic to detect `push %rbp`
+(`push %ebp` on 32-bit architecture) instruction being traced. Given
+entire kernel implementation of user space stack trace capturing works
+under assumption that user space code was compiled with frame pointer
+register (%rbp/%ebp) preservation, it seems pretty reasonable to use
+this instruction as a strong indicator that this is the entry to the
+function. In that case, return address is still pointed to by %rsp/%esp,
+so we fetch it and add to stack trace before proceeding to unwind the
+rest using frame pointer-based logic.
+
+We also check for `endbr64` (for 64-bit modes) as another common pattern
+for function entry, as suggested by Josh Poimboeuf. Even if we get this
+wrong sometimes for uprobes attached not at the function entry, it's OK
+because stack trace will still be overall meaningful, just with one
+extra bogus entry. If we don't detect this, we end up with guaranteed to
+be missing caller function entry in the stack trace, which is worse
+overall.
+
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://lkml.kernel.org/r/20240729175223.23914-1-andrii@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/events/core.c  | 63 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/uprobes.h |  2 ++
+ kernel/events/uprobes.c |  2 ++
+ 3 files changed, 67 insertions(+)
+
+diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
+index 83d12dd3f831a..d77a97056844b 100644
+--- a/arch/x86/events/core.c
++++ b/arch/x86/events/core.c
+@@ -41,6 +41,8 @@
+ #include <asm/desc.h>
+ #include <asm/ldt.h>
+ #include <asm/unwind.h>
++#include <asm/uprobes.h>
++#include <asm/ibt.h>
+ #include "perf_event.h"
+@@ -2814,6 +2816,46 @@ static unsigned long get_segment_base(unsigned int segment)
+       return get_desc_base(desc);
+ }
++#ifdef CONFIG_UPROBES
++/*
++ * Heuristic-based check if uprobe is installed at the function entry.
++ *
++ * Under assumption of user code being compiled with frame pointers,
++ * `push %rbp/%ebp` is a good indicator that we indeed are.
++ *
++ * Similarly, `endbr64` (assuming 64-bit mode) is also a common pattern.
++ * If we get this wrong, captured stack trace might have one extra bogus
++ * entry, but the rest of stack trace will still be meaningful.
++ */
++static bool is_uprobe_at_func_entry(struct pt_regs *regs)
++{
++      struct arch_uprobe *auprobe;
++
++      if (!current->utask)
++              return false;
++
++      auprobe = current->utask->auprobe;
++      if (!auprobe)
++              return false;
++
++      /* push %rbp/%ebp */
++      if (auprobe->insn[0] == 0x55)
++              return true;
++
++      /* endbr64 (64-bit only) */
++      if (user_64bit_mode(regs) && is_endbr(*(u32 *)auprobe->insn))
++              return true;
++
++      return false;
++}
++
++#else
++static bool is_uprobe_at_func_entry(struct pt_regs *regs)
++{
++      return false;
++}
++#endif /* CONFIG_UPROBES */
++
+ #ifdef CONFIG_IA32_EMULATION
+ #include <linux/compat.h>
+@@ -2825,6 +2867,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
+       unsigned long ss_base, cs_base;
+       struct stack_frame_ia32 frame;
+       const struct stack_frame_ia32 __user *fp;
++      u32 ret_addr;
+       if (user_64bit_mode(regs))
+               return 0;
+@@ -2834,6 +2877,12 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
+       fp = compat_ptr(ss_base + regs->bp);
+       pagefault_disable();
++
++      /* see perf_callchain_user() below for why we do this */
++      if (is_uprobe_at_func_entry(regs) &&
++          !get_user(ret_addr, (const u32 __user *)regs->sp))
++              perf_callchain_store(entry, ret_addr);
++
+       while (entry->nr < entry->max_stack) {
+               if (!valid_user_frame(fp, sizeof(frame)))
+                       break;
+@@ -2862,6 +2911,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
+ {
+       struct stack_frame frame;
+       const struct stack_frame __user *fp;
++      unsigned long ret_addr;
+       if (perf_guest_state()) {
+               /* TODO: We don't support guest os callchain now */
+@@ -2885,6 +2935,19 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
+               return;
+       pagefault_disable();
++
++      /*
++       * If we are called from uprobe handler, and we are indeed at the very
++       * entry to user function (which is normally a `push %rbp` instruction,
++       * under assumption of application being compiled with frame pointers),
++       * we should read return address from *regs->sp before proceeding
++       * to follow frame pointers, otherwise we'll skip immediate caller
++       * as %rbp is not yet setup.
++       */
++      if (is_uprobe_at_func_entry(regs) &&
++          !get_user(ret_addr, (const unsigned long __user *)regs->sp))
++              perf_callchain_store(entry, ret_addr);
++
+       while (entry->nr < entry->max_stack) {
+               if (!valid_user_frame(fp, sizeof(frame)))
+                       break;
+diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
+index f46e0ca0169c7..d91e32aff5a13 100644
+--- a/include/linux/uprobes.h
++++ b/include/linux/uprobes.h
+@@ -76,6 +76,8 @@ struct uprobe_task {
+       struct uprobe                   *active_uprobe;
+       unsigned long                   xol_vaddr;
++      struct arch_uprobe              *auprobe;
++
+       struct return_instance          *return_instances;
+       unsigned int                    depth;
+ };
+diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
+index 47cdec3e1df11..28c678c8daef3 100644
+--- a/kernel/events/uprobes.c
++++ b/kernel/events/uprobes.c
+@@ -2071,6 +2071,7 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+       bool need_prep = false; /* prepare return uprobe, when needed */
+       down_read(&uprobe->register_rwsem);
++      current->utask->auprobe = &uprobe->arch;
+       for (uc = uprobe->consumers; uc; uc = uc->next) {
+               int rc = 0;
+@@ -2085,6 +2086,7 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+               remove &= rc;
+       }
++      current->utask->auprobe = NULL;
+       if (need_prep && !remove)
+               prepare_uretprobe(uprobe, regs); /* put bp at return */
+-- 
+2.43.0
+
diff --git a/queue-6.10/platform-mellanox-mlxbf-pmc-fix-lockdep-warning.patch b/queue-6.10/platform-mellanox-mlxbf-pmc-fix-lockdep-warning.patch
new file mode 100644 (file)
index 0000000..e5fad47
--- /dev/null
@@ -0,0 +1,135 @@
+From 2a40f56da1acfca4e814859606bae5f2a23c3cff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:05:32 -0400
+Subject: platform/mellanox: mlxbf-pmc: fix lockdep warning
+
+From: Luiz Capitulino <luizcap@redhat.com>
+
+[ Upstream commit 305790dd91057a3f7497c9d128614a4f8486b62b ]
+
+It seems the mlxbf-pmc driver is missing initializing sysfs attributes
+which causes the warning below when CONFIG_LOCKDEP and
+CONFIG_DEBUG_LOCK_ALLOC are enabled. This commit fixes it.
+
+[  155.380843] BUG: key ffff470f45dfa6d8 has not been registered!
+[  155.386749] ------------[ cut here ]------------
+[  155.391361] DEBUG_LOCKS_WARN_ON(1)
+[  155.391381] WARNING: CPU: 4 PID: 1828 at kernel/locking/lockdep.c:4894 lockdep_init_map_type+0x1d0/0x288
+[  155.404254] Modules linked in: mlxbf_pmc(+) xfs libcrc32c mmc_block mlx5_core crct10dif_ce mlxfw ghash_ce virtio_net tls net_failover sha2
+_ce failover psample sha256_arm64 dw_mmc_bluefield pci_hyperv_intf sha1_ce dw_mmc_pltfm sbsa_gwdt dw_mmc micrel mmc_core nfit i2c_mlxbf pwr_m
+lxbf gpio_generic libnvdimm mlxbf_tmfifo mlxbf_gige dm_mirror dm_region_hash dm_log dm_mod
+[  155.436786] CPU: 4 UID: 0 PID: 1828 Comm: modprobe Kdump: loaded Not tainted 6.11.0-rc7-rep1+ #1
+[  155.445562] Hardware name: https://www.mellanox.com BlueField SoC/BlueField SoC, BIOS 4.8.0.13249 Aug  7 2024
+[  155.455463] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
+[  155.462413] pc : lockdep_init_map_type+0x1d0/0x288
+[  155.467196] lr : lockdep_init_map_type+0x1d0/0x288
+[  155.471976] sp : ffff80008a1734e0
+[  155.475279] x29: ffff80008a1734e0 x28: ffff470f45df0240 x27: 00000000ffffee4b
+[  155.482406] x26: 00000000000011b4 x25: 0000000000000000 x24: 0000000000000000
+[  155.489532] x23: ffff470f45dfa6d8 x22: 0000000000000000 x21: ffffd54ef6bea000
+[  155.496659] x20: ffff470f45dfa6d8 x19: ffff470f49cdc638 x18: ffffffffffffffff
+[  155.503784] x17: 2f30303a31444642 x16: ffffd54ef48a65e8 x15: ffff80010a172fe7
+[  155.510911] x14: 0000000000000000 x13: 284e4f5f4e524157 x12: 5f534b434f4c5f47
+[  155.518037] x11: 0000000000000001 x10: 0000000000000001 x9 : ffffd54ef3f48a14
+[  155.525163] x8 : 00000000000bffe8 x7 : c0000000ffff7fff x6 : 00000000002bffa8
+[  155.532289] x5 : ffff4712bdcb6088 x4 : 0000000000000000 x3 : 0000000000000027
+[  155.539416] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff470f43e5be00
+[  155.546542] Call trace:
+[  155.548976]  lockdep_init_map_type+0x1d0/0x288
+[  155.553410]  __kernfs_create_file+0x80/0x138
+[  155.557673]  sysfs_add_file_mode_ns+0x94/0x150
+[  155.562106]  create_files+0xb0/0x248
+[  155.565672]  internal_create_group+0x10c/0x328
+[  155.570105]  internal_create_groups.part.0+0x50/0xc8
+[  155.575060]  sysfs_create_groups+0x20/0x38
+[  155.579146]  device_add_attrs+0x1b8/0x228
+[  155.583146]  device_add+0x2a4/0x690
+[  155.586625]  device_register+0x24/0x38
+[  155.590362]  __hwmon_device_register+0x1e0/0x3c8
+[  155.594969]  devm_hwmon_device_register_with_groups+0x78/0xe0
+[  155.600703]  mlxbf_pmc_probe+0x224/0x3a0 [mlxbf_pmc]
+[  155.605669]  platform_probe+0x6c/0xe0
+[  155.609320]  really_probe+0xc4/0x398
+[  155.612887]  __driver_probe_device+0x80/0x168
+[  155.617233]  driver_probe_device+0x44/0x120
+[  155.621405]  __driver_attach+0xf4/0x200
+[  155.625230]  bus_for_each_dev+0x7c/0xe8
+[  155.629055]  driver_attach+0x28/0x38
+[  155.632619]  bus_add_driver+0x110/0x238
+[  155.636445]  driver_register+0x64/0x128
+[  155.640270]  __platform_driver_register+0x2c/0x40
+[  155.644965]  pmc_driver_init+0x24/0xff8 [mlxbf_pmc]
+[  155.649833]  do_one_initcall+0x70/0x3d0
+[  155.653660]  do_init_module+0x64/0x220
+[  155.657400]  load_module+0x628/0x6a8
+[  155.660964]  init_module_from_file+0x8c/0xd8
+[  155.665222]  idempotent_init_module+0x194/0x290
+[  155.669742]  __arm64_sys_finit_module+0x6c/0xd8
+[  155.674261]  invoke_syscall.constprop.0+0x74/0xd0
+[  155.678957]  do_el0_svc+0xb4/0xd0
+[  155.682262]  el0_svc+0x5c/0x248
+[  155.685394]  el0t_64_sync_handler+0x134/0x150
+[  155.689739]  el0t_64_sync+0x17c/0x180
+[  155.693390] irq event stamp: 6407
+[  155.696693] hardirqs last  enabled at (6407): [<ffffd54ef3f48564>] console_unlock+0x154/0x1b8
+[  155.705207] hardirqs last disabled at (6406): [<ffffd54ef3f485ac>] console_unlock+0x19c/0x1b8
+[  155.713719] softirqs last  enabled at (6404): [<ffffd54ef3e9740c>] handle_softirqs+0x4f4/0x518
+[  155.722320] softirqs last disabled at (6395): [<ffffd54ef3df0160>] __do_softirq+0x18/0x20
+[  155.730484] ---[ end trace 0000000000000000 ]---
+
+Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
+Link: https://lore.kernel.org/r/20240912190532.377097-1-luizcap@redhat.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/mellanox/mlxbf-pmc.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c
+index 4ed9c7fd2b62a..9d18dfca6a673 100644
+--- a/drivers/platform/mellanox/mlxbf-pmc.c
++++ b/drivers/platform/mellanox/mlxbf-pmc.c
+@@ -1774,6 +1774,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+       /* "event_list" sysfs to list events supported by the block */
+       attr = &pmc->block[blk_num].attr_event_list;
++      sysfs_attr_init(&attr->dev_attr.attr);
+       attr->dev_attr.attr.mode = 0444;
+       attr->dev_attr.show = mlxbf_pmc_event_list_show;
+       attr->nr = blk_num;
+@@ -1787,6 +1788,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+       if (strstr(pmc->block_name[blk_num], "l3cache") ||
+           ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) {
+               attr = &pmc->block[blk_num].attr_enable;
++              sysfs_attr_init(&attr->dev_attr.attr);
+               attr->dev_attr.attr.mode = 0644;
+               attr->dev_attr.show = mlxbf_pmc_enable_show;
+               attr->dev_attr.store = mlxbf_pmc_enable_store;
+@@ -1814,6 +1816,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+       /* "eventX" and "counterX" sysfs to program and read counter values */
+       for (j = 0; j < pmc->block[blk_num].counters; ++j) {
+               attr = &pmc->block[blk_num].attr_counter[j];
++              sysfs_attr_init(&attr->dev_attr.attr);
+               attr->dev_attr.attr.mode = 0644;
+               attr->dev_attr.show = mlxbf_pmc_counter_show;
+               attr->dev_attr.store = mlxbf_pmc_counter_store;
+@@ -1826,6 +1829,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
+               attr = NULL;
+               attr = &pmc->block[blk_num].attr_event[j];
++              sysfs_attr_init(&attr->dev_attr.attr);
+               attr->dev_attr.attr.mode = 0644;
+               attr->dev_attr.show = mlxbf_pmc_event_show;
+               attr->dev_attr.store = mlxbf_pmc_event_store;
+@@ -1861,6 +1865,7 @@ static int mlxbf_pmc_init_perftype_reg(struct device *dev, unsigned int blk_num)
+       while (count > 0) {
+               --count;
+               attr = &pmc->block[blk_num].attr_event[count];
++              sysfs_attr_init(&attr->dev_attr.attr);
+               attr->dev_attr.attr.mode = 0644;
+               attr->dev_attr.show = mlxbf_pmc_counter_show;
+               attr->dev_attr.store = mlxbf_pmc_counter_store;
+-- 
+2.43.0
+
diff --git a/queue-6.10/platform-x86-amd-pmf-add-quirk-for-tuf-gaming-a14.patch b/queue-6.10/platform-x86-amd-pmf-add-quirk-for-tuf-gaming-a14.patch
new file mode 100644 (file)
index 0000000..78d554c
--- /dev/null
@@ -0,0 +1,44 @@
+From c8fd75c09199bd4c69bbde30f934768d445246e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:36:01 +0800
+Subject: platform/x86/amd: pmf: Add quirk for TUF Gaming A14
+
+From: aln8 <aln8un@gmail.com>
+
+[ Upstream commit 06369503d644068abd9e90918c6611274d94c126 ]
+
+The ASUS TUF Gaming A14 has the same issue as the ROG Zephyrus G14
+where it advertises SPS support but doesn't use it.
+
+Signed-off-by: aln8 <aln8un@gmail.com>
+Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Link: https://lore.kernel.org/r/20240912073601.65656-1-aln8un@gmail.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/amd/pmf/pmf-quirks.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/platform/x86/amd/pmf/pmf-quirks.c b/drivers/platform/x86/amd/pmf/pmf-quirks.c
+index 48870ca52b413..7cde5733b9cac 100644
+--- a/drivers/platform/x86/amd/pmf/pmf-quirks.c
++++ b/drivers/platform/x86/amd/pmf/pmf-quirks.c
+@@ -37,6 +37,14 @@ static const struct dmi_system_id fwbug_list[] = {
+               },
+               .driver_data = &quirk_no_sps_bug,
+       },
++      {
++              .ident = "ASUS TUF Gaming A14",
++              .matches = {
++                      DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++                      DMI_MATCH(DMI_PRODUCT_NAME, "FA401W"),
++              },
++              .driver_data = &quirk_no_sps_bug,
++      },
+       {}
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.10/platform-x86-lenovo-ymc-ignore-the-0x0-state.patch b/queue-6.10/platform-x86-lenovo-ymc-ignore-the-0x0-state.patch
new file mode 100644 (file)
index 0000000..add5c00
--- /dev/null
@@ -0,0 +1,46 @@
+From 0999daecd7f1100e089cdaf19bd2bb0bfdf3ccb1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 17:38:57 +0200
+Subject: platform/x86: lenovo-ymc: Ignore the 0x0 state
+
+From: Gergo Koteles <soyer@irl.hu>
+
+[ Upstream commit d9dca215708d32e7f88ac0591fbb187cbf368adb ]
+
+While booting, Lenovo 14ARB7 reports 'lenovo-ymc: Unknown key 0 pressed'
+warning. This is caused by lenovo_ymc_probe() calling lenovo_ymc_notify()
+at probe time to get the initial tablet-mode-switch state and the key-code
+lenovo_ymc_notify() reads from the firmware is not initialized at probe
+time yet on the Lenovo 14ARB7.
+
+The hardware/firmware does an ACPI notify on the WMI device itself when
+it initializes the tablet-mode-switch state later on.
+
+Add 0x0 YMC state to the sparse keymap to silence the warning.
+
+Signed-off-by: Gergo Koteles <soyer@irl.hu>
+Link: https://lore.kernel.org/r/08ab73bb74c4ad448409f2ce707b1148874a05ce.1724340562.git.soyer@irl.hu
+[hdegoede@redhat.com: Reword commit message]
+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/lenovo-ymc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c
+index e0bbd6a14a89c..bd9f95404c7cb 100644
+--- a/drivers/platform/x86/lenovo-ymc.c
++++ b/drivers/platform/x86/lenovo-ymc.c
+@@ -43,6 +43,8 @@ struct lenovo_ymc_private {
+ };
+ static const struct key_entry lenovo_ymc_keymap[] = {
++      /* Ignore the uninitialized state */
++      { KE_IGNORE, 0x00 },
+       /* Laptop */
+       { KE_SW, 0x01, { .sw = { SW_TABLET_MODE, 0 } } },
+       /* Tablet */
+-- 
+2.43.0
+
diff --git a/queue-6.10/platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch b/queue-6.10/platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch
new file mode 100644 (file)
index 0000000..2eba9a8
--- /dev/null
@@ -0,0 +1,69 @@
+From bb5eb37aafeb6b0a1813b8f138f8c40d826c7727 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 21:12:40 +0200
+Subject: platform/x86: touchscreen_dmi: add nanote-next quirk
+
+From: Ckath <ckath@yandex.ru>
+
+[ Upstream commit c11619af35bae5884029bd14170c3e4b55ddf6f3 ]
+
+Add touschscreen info for the nanote next (UMPC-03-SR).
+
+After checking with multiple owners the DMI info really is this generic.
+
+Signed-off-by: Ckath <ckath@yandex.ru>
+Link: https://lore.kernel.org/r/e8dda83a-10ae-42cf-a061-5d29be0d193a@yandex.ru
+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/touchscreen_dmi.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
+index f74af0a689f20..0a39f68c641d1 100644
+--- a/drivers/platform/x86/touchscreen_dmi.c
++++ b/drivers/platform/x86/touchscreen_dmi.c
+@@ -840,6 +840,21 @@ static const struct ts_dmi_data rwc_nanote_p8_data = {
+       .properties = rwc_nanote_p8_props,
+ };
++static const struct property_entry rwc_nanote_next_props[] = {
++      PROPERTY_ENTRY_U32("touchscreen-min-x", 5),
++      PROPERTY_ENTRY_U32("touchscreen-min-y", 5),
++      PROPERTY_ENTRY_U32("touchscreen-size-x", 1785),
++      PROPERTY_ENTRY_U32("touchscreen-size-y", 1145),
++      PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
++      PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-next.fw"),
++      { }
++};
++
++static const struct ts_dmi_data rwc_nanote_next_data = {
++      .acpi_name = "MSSL1680:00",
++      .properties = rwc_nanote_next_props,
++};
++
+ static const struct property_entry schneider_sct101ctm_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+@@ -1589,6 +1604,17 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
+                       DMI_MATCH(DMI_PRODUCT_SKU, "0001")
+               },
+       },
++      {
++              /* RWC NANOTE NEXT */
++              .driver_data = (void *)&rwc_nanote_next_data,
++              .matches = {
++                      DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
++                      DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),
++                      DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
++                      /* Above matches are too generic, add bios-version match */
++                      DMI_MATCH(DMI_BIOS_VERSION, "S8A70R100-V005"),
++              },
++      },
+       {
+               /* Schneider SCT101CTM */
+               .driver_data = (void *)&schneider_sct101ctm_data,
+-- 
+2.43.0
+
diff --git a/queue-6.10/platform-x86-x86-android-tablets-adjust-xiaomi-pad-2.patch b/queue-6.10/platform-x86-x86-android-tablets-adjust-xiaomi-pad-2.patch
new file mode 100644 (file)
index 0000000..d4aa3a7
--- /dev/null
@@ -0,0 +1,70 @@
+From e8087bfbd9900fcfed60efa0efbb250858c5dd67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Sep 2024 11:02:55 +0200
+Subject: platform/x86: x86-android-tablets: Adjust Xiaomi Pad 2 bottom bezel
+ touch buttons LED
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit df40a23cc34c200cfde559eda7ca540f3ae7bd9e ]
+
+The "input-events" LED trigger used to turn on the backlight LEDs had to
+be rewritten to use led_trigger_register_simple() + led_trigger_event()
+to fix a serious locking issue.
+
+This means it no longer supports using blink_brightness to set a per LED
+brightness for the trigger and it no longer sets LED_CORE_SUSPENDRESUME.
+
+Adjust the MiPad 2 bottom bezel touch buttons LED class device to match:
+
+1. Make LED_FULL the maximum brightness to fix the LED brightness
+   being very low when on.
+2. Set flags = LED_CORE_SUSPENDRESUME.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20240916090255.35548-1-hdegoede@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/x86-android-tablets/other.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c
+index eb0e55c69dfed..2549c348c8825 100644
+--- a/drivers/platform/x86/x86-android-tablets/other.c
++++ b/drivers/platform/x86/x86-android-tablets/other.c
+@@ -670,7 +670,7 @@ static const struct software_node *ktd2026_node_group[] = {
+  * is controlled by the "pwm_soc_lpss_2" PWM output.
+  */
+ #define XIAOMI_MIPAD2_LED_PERIOD_NS           19200
+-#define XIAOMI_MIPAD2_LED_DEFAULT_DUTY                 6000 /* From Android kernel */
++#define XIAOMI_MIPAD2_LED_MAX_DUTY_NS          6000 /* From Android kernel */
+ static struct pwm_device *xiaomi_mipad2_led_pwm;
+@@ -679,7 +679,7 @@ static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
+ {
+       struct pwm_state state = {
+               .period = XIAOMI_MIPAD2_LED_PERIOD_NS,
+-              .duty_cycle = val,
++              .duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
+               /* Always set PWM enabled to avoid the pin floating */
+               .enabled = true,
+       };
+@@ -701,11 +701,11 @@ static int __init xiaomi_mipad2_init(struct device *dev)
+               return -ENOMEM;
+       led_cdev->name = "mipad2:white:touch-buttons-backlight";
+-      led_cdev->max_brightness = XIAOMI_MIPAD2_LED_PERIOD_NS;
+-      /* "input-events" trigger uses blink_brightness */
+-      led_cdev->blink_brightness = XIAOMI_MIPAD2_LED_DEFAULT_DUTY;
++      led_cdev->max_brightness = LED_FULL;
+       led_cdev->default_trigger = "input-events";
+       led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
++      /* Turn LED off during suspend */
++      led_cdev->flags = LED_CORE_SUSPENDRESUME;
+       ret = devm_led_classdev_register(dev, led_cdev);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-6.10/pmdomain-core-don-t-hold-the-genpd-lock-when-calling.patch b/queue-6.10/pmdomain-core-don-t-hold-the-genpd-lock-when-calling.patch
new file mode 100644 (file)
index 0000000..af22010
--- /dev/null
@@ -0,0 +1,65 @@
+From 98f8d5886c9ab96dab11b5ea593d58f59f70e3b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 May 2024 16:25:52 +0200
+Subject: pmdomain: core: Don't hold the genpd-lock when calling
+ dev_pm_domain_set()
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+[ Upstream commit b87eee38605c396f0e1fa435939960e5c6cd41d6 ]
+
+There is no need to hold the genpd-lock, while assigning the
+dev->pm_domain. In fact, it becomes a problem on a PREEMPT_RT based
+configuration as the genpd-lock may be a raw spinlock, while the lock
+acquired through the call to dev_pm_domain_set() is a regular spinlock.
+
+To fix the problem, let's simply move the calls to dev_pm_domain_set()
+outside the genpd-lock.
+
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Tested-by: Raghavendra Kakarla <quic_rkakarla@quicinc.com>  # qcm6490 with PREEMPT_RT set
+Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20240527142557.321610-3-ulf.hansson@linaro.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pmdomain/core.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
+index 0ab6008e863e8..4134a8344d2da 100644
+--- a/drivers/pmdomain/core.c
++++ b/drivers/pmdomain/core.c
+@@ -1694,7 +1694,6 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
+       genpd_lock(genpd);
+       genpd_set_cpumask(genpd, gpd_data->cpu);
+-      dev_pm_domain_set(dev, &genpd->domain);
+       genpd->device_count++;
+       if (gd)
+@@ -1703,6 +1702,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
+       list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+       genpd_unlock(genpd);
++      dev_pm_domain_set(dev, &genpd->domain);
+  out:
+       if (ret)
+               genpd_free_dev_data(dev, gpd_data);
+@@ -1759,12 +1759,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
+               genpd->gd->max_off_time_changed = true;
+       genpd_clear_cpumask(genpd, gpd_data->cpu);
+-      dev_pm_domain_set(dev, NULL);
+       list_del_init(&pdd->list_node);
+       genpd_unlock(genpd);
++      dev_pm_domain_set(dev, NULL);
++
+       if (genpd->detach_dev)
+               genpd->detach_dev(genpd, dev);
+-- 
+2.43.0
+
diff --git a/queue-6.10/power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch b/queue-6.10/power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch
new file mode 100644 (file)
index 0000000..e29cf27
--- /dev/null
@@ -0,0 +1,39 @@
+From 8389003eca426ab13f51e908c3034ec0e4a56de2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jun 2024 09:28:36 -0500
+Subject: power: reset: brcmstb: Do not go into infinite loop if reset fails
+
+From: Andrew Davis <afd@ti.com>
+
+[ Upstream commit cf8c39b00e982fa506b16f9d76657838c09150cb ]
+
+There may be other backup reset methods available, do not halt
+here so that other reset methods can be tried.
+
+Signed-off-by: Andrew Davis <afd@ti.com>
+Reviewed-by: Dhruva Gole <d-gole@ti.com>
+Acked-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://lore.kernel.org/r/20240610142836.168603-5-afd@ti.com
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/power/reset/brcmstb-reboot.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c
+index 0f2944dc93551..a04713f191a11 100644
+--- a/drivers/power/reset/brcmstb-reboot.c
++++ b/drivers/power/reset/brcmstb-reboot.c
+@@ -62,9 +62,6 @@ static int brcmstb_restart_handler(struct notifier_block *this,
+               return NOTIFY_DONE;
+       }
+-      while (1)
+-              ;
+-
+       return NOTIFY_DONE;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/powerpc-pseries-use-correct-data-types-from-pseries_.patch b/queue-6.10/powerpc-pseries-use-correct-data-types-from-pseries_.patch
new file mode 100644 (file)
index 0000000..c2d6ee8
--- /dev/null
@@ -0,0 +1,157 @@
+From 2ee66c001378c865bf341a1eda4eea5b6580d93e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 19:50:26 -0700
+Subject: powerpc/pseries: Use correct data types from pseries_hp_errorlog
+ struct
+
+From: Haren Myneni <haren@linux.ibm.com>
+
+[ Upstream commit b76e0d4215b6b622127ebcceaa7f603313ceaec4 ]
+
+_be32 type is defined for some elements in pseries_hp_errorlog
+struct but also used them u32 after be32_to_cpu() conversion.
+
+Example: In handle_dlpar_errorlog()
+hp_elog->_drc_u.drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+
+And later assigned to u32 type
+dlpar_cpu() - u32 drc_index = hp_elog->_drc_u.drc_index;
+
+This incorrect usage is giving the following warnings and the
+patch resolve these warnings with the correct assignment.
+
+arch/powerpc/platforms/pseries/dlpar.c:398:53: sparse: sparse:
+incorrect type in argument 1 (different base types) @@
+expected unsigned int [usertype] drc_index @@
+got restricted __be32 [usertype] drc_index @@
+...
+arch/powerpc/platforms/pseries/dlpar.c:418:43: sparse: sparse:
+incorrect type in assignment (different base types) @@
+expected restricted __be32 [usertype] drc_count @@
+got unsigned int [usertype] @@
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202408182142.wuIKqYae-lkp@intel.com/
+Closes: https://lore.kernel.org/oe-kbuild-all/202408182302.o7QRO45S-lkp@intel.com/
+Signed-off-by: Haren Myneni <haren@linux.ibm.com>
+
+v3:
+- Fix warnings from using incorrect data types in pseries_hp_errorlog
+  struct
+v2:
+- Remove pr_info() and TODO comments
+- Update more information in the commit logs
+
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://msgid.link/20240822025028.938332-1-haren@linux.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/platforms/pseries/dlpar.c          | 17 -----------------
+ arch/powerpc/platforms/pseries/hotplug-cpu.c    |  2 +-
+ arch/powerpc/platforms/pseries/hotplug-memory.c | 16 ++++++++--------
+ arch/powerpc/platforms/pseries/pmem.c           |  2 +-
+ 4 files changed, 10 insertions(+), 27 deletions(-)
+
+diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
+index 47f8eabd1bee3..9873b916b2370 100644
+--- a/arch/powerpc/platforms/pseries/dlpar.c
++++ b/arch/powerpc/platforms/pseries/dlpar.c
+@@ -334,23 +334,6 @@ int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
+ {
+       int rc;
+-      /* pseries error logs are in BE format, convert to cpu type */
+-      switch (hp_elog->id_type) {
+-      case PSERIES_HP_ELOG_ID_DRC_COUNT:
+-              hp_elog->_drc_u.drc_count =
+-                              be32_to_cpu(hp_elog->_drc_u.drc_count);
+-              break;
+-      case PSERIES_HP_ELOG_ID_DRC_INDEX:
+-              hp_elog->_drc_u.drc_index =
+-                              be32_to_cpu(hp_elog->_drc_u.drc_index);
+-              break;
+-      case PSERIES_HP_ELOG_ID_DRC_IC:
+-              hp_elog->_drc_u.ic.count =
+-                              be32_to_cpu(hp_elog->_drc_u.ic.count);
+-              hp_elog->_drc_u.ic.index =
+-                              be32_to_cpu(hp_elog->_drc_u.ic.index);
+-      }
+-
+       switch (hp_elog->resource) {
+       case PSERIES_HP_ELOG_RESOURCE_MEM:
+               rc = dlpar_memory(hp_elog);
+diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
+index e62835a12d73f..6838a0fcda296 100644
+--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
++++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
+@@ -757,7 +757,7 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
+       u32 drc_index;
+       int rc;
+-      drc_index = hp_elog->_drc_u.drc_index;
++      drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+       lock_device_hotplug();
+diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
+index 3fe3ddb30c04b..38dc4f7c9296b 100644
+--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
++++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
+@@ -817,16 +817,16 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
+       case PSERIES_HP_ELOG_ACTION_ADD:
+               switch (hp_elog->id_type) {
+               case PSERIES_HP_ELOG_ID_DRC_COUNT:
+-                      count = hp_elog->_drc_u.drc_count;
++                      count = be32_to_cpu(hp_elog->_drc_u.drc_count);
+                       rc = dlpar_memory_add_by_count(count);
+                       break;
+               case PSERIES_HP_ELOG_ID_DRC_INDEX:
+-                      drc_index = hp_elog->_drc_u.drc_index;
++                      drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+                       rc = dlpar_memory_add_by_index(drc_index);
+                       break;
+               case PSERIES_HP_ELOG_ID_DRC_IC:
+-                      count = hp_elog->_drc_u.ic.count;
+-                      drc_index = hp_elog->_drc_u.ic.index;
++                      count = be32_to_cpu(hp_elog->_drc_u.ic.count);
++                      drc_index = be32_to_cpu(hp_elog->_drc_u.ic.index);
+                       rc = dlpar_memory_add_by_ic(count, drc_index);
+                       break;
+               default:
+@@ -838,16 +838,16 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
+       case PSERIES_HP_ELOG_ACTION_REMOVE:
+               switch (hp_elog->id_type) {
+               case PSERIES_HP_ELOG_ID_DRC_COUNT:
+-                      count = hp_elog->_drc_u.drc_count;
++                      count = be32_to_cpu(hp_elog->_drc_u.drc_count);
+                       rc = dlpar_memory_remove_by_count(count);
+                       break;
+               case PSERIES_HP_ELOG_ID_DRC_INDEX:
+-                      drc_index = hp_elog->_drc_u.drc_index;
++                      drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+                       rc = dlpar_memory_remove_by_index(drc_index);
+                       break;
+               case PSERIES_HP_ELOG_ID_DRC_IC:
+-                      count = hp_elog->_drc_u.ic.count;
+-                      drc_index = hp_elog->_drc_u.ic.index;
++                      count = be32_to_cpu(hp_elog->_drc_u.ic.count);
++                      drc_index = be32_to_cpu(hp_elog->_drc_u.ic.index);
+                       rc = dlpar_memory_remove_by_ic(count, drc_index);
+                       break;
+               default:
+diff --git a/arch/powerpc/platforms/pseries/pmem.c b/arch/powerpc/platforms/pseries/pmem.c
+index 3c290b9ed01b3..0f1d45f32e4a4 100644
+--- a/arch/powerpc/platforms/pseries/pmem.c
++++ b/arch/powerpc/platforms/pseries/pmem.c
+@@ -121,7 +121,7 @@ int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog)
+               return -EINVAL;
+       }
+-      drc_index = hp_elog->_drc_u.drc_index;
++      drc_index = be32_to_cpu(hp_elog->_drc_u.drc_index);
+       lock_device_hotplug();
+-- 
+2.43.0
+
diff --git a/queue-6.10/proc-add-config-param-to-block-forcing-mem-writes.patch b/queue-6.10/proc-add-config-param-to-block-forcing-mem-writes.patch
new file mode 100644 (file)
index 0000000..5dac8c1
--- /dev/null
@@ -0,0 +1,200 @@
+From ec7e21060791ea3fe19dcf7480f5f2669ba287c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 11:02:25 +0300
+Subject: proc: add config & param to block forcing mem writes
+
+From: Adrian Ratiu <adrian.ratiu@collabora.com>
+
+[ Upstream commit 41e8149c8892ed1962bd15350b3c3e6e90cba7f4 ]
+
+This adds a Kconfig option and boot param to allow removing
+the FOLL_FORCE flag from /proc/pid/mem write calls because
+it can be abused.
+
+The traditional forcing behavior is kept as default because
+it can break GDB and some other use cases.
+
+Previously we tried a more sophisticated approach allowing
+distributions to fine-tune /proc/pid/mem behavior, however
+that got NAK-ed by Linus [1], who prefers this simpler
+approach with semantics also easier to understand for users.
+
+Link: https://lore.kernel.org/lkml/CAHk-=wiGWLChxYmUA5HrT5aopZrB7_2VTa0NLZcxORgkUe5tEQ@mail.gmail.com/ [1]
+Cc: Doug Anderson <dianders@chromium.org>
+Cc: Jeff Xu <jeffxu@google.com>
+Cc: Jann Horn <jannh@google.com>
+Cc: Kees Cook <kees@kernel.org>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Christian Brauner <brauner@kernel.org>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
+Link: https://lore.kernel.org/r/20240802080225.89408-1-adrian.ratiu@collabora.com
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../admin-guide/kernel-parameters.txt         | 10 +++
+ fs/proc/base.c                                | 61 ++++++++++++++++++-
+ security/Kconfig                              | 32 ++++++++++
+ 3 files changed, 102 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
+index c82446cef8e21..2c8e062eb2ce5 100644
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -4791,6 +4791,16 @@
+       printk.time=    Show timing data prefixed to each printk message line
+                       Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
++      proc_mem.force_override= [KNL]
++                      Format: {always | ptrace | never}
++                      Traditionally /proc/pid/mem allows memory permissions to be
++                      overridden without restrictions. This option may be set to
++                      restrict that. Can be one of:
++                      - 'always': traditional behavior always allows mem overrides.
++                      - 'ptrace': only allow mem overrides for active ptracers.
++                      - 'never':  never allow mem overrides.
++                      If not specified, default is the CONFIG_PROC_MEM_* choice.
++
+       processor.max_cstate=   [HW,ACPI]
+                       Limit processor to maximum C-state
+                       max_cstate=9 overrides any DMI blacklist limit.
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 72a1acd03675c..f389c69767fa5 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -85,6 +85,7 @@
+ #include <linux/elf.h>
+ #include <linux/pid_namespace.h>
+ #include <linux/user_namespace.h>
++#include <linux/fs_parser.h>
+ #include <linux/fs_struct.h>
+ #include <linux/slab.h>
+ #include <linux/sched/autogroup.h>
+@@ -117,6 +118,40 @@
+ static u8 nlink_tid __ro_after_init;
+ static u8 nlink_tgid __ro_after_init;
++enum proc_mem_force {
++      PROC_MEM_FORCE_ALWAYS,
++      PROC_MEM_FORCE_PTRACE,
++      PROC_MEM_FORCE_NEVER
++};
++
++static enum proc_mem_force proc_mem_force_override __ro_after_init =
++      IS_ENABLED(CONFIG_PROC_MEM_NO_FORCE) ? PROC_MEM_FORCE_NEVER :
++      IS_ENABLED(CONFIG_PROC_MEM_FORCE_PTRACE) ? PROC_MEM_FORCE_PTRACE :
++      PROC_MEM_FORCE_ALWAYS;
++
++static const struct constant_table proc_mem_force_table[] __initconst = {
++      { "always", PROC_MEM_FORCE_ALWAYS },
++      { "ptrace", PROC_MEM_FORCE_PTRACE },
++      { "never", PROC_MEM_FORCE_NEVER },
++      { }
++};
++
++static int __init early_proc_mem_force_override(char *buf)
++{
++      if (!buf)
++              return -EINVAL;
++
++      /*
++       * lookup_constant() defaults to proc_mem_force_override to preseve
++       * the initial Kconfig choice in case an invalid param gets passed.
++       */
++      proc_mem_force_override = lookup_constant(proc_mem_force_table,
++                                                buf, proc_mem_force_override);
++
++      return 0;
++}
++early_param("proc_mem.force_override", early_proc_mem_force_override);
++
+ struct pid_entry {
+       const char *name;
+       unsigned int len;
+@@ -835,6 +870,28 @@ static int mem_open(struct inode *inode, struct file *file)
+       return ret;
+ }
++static bool proc_mem_foll_force(struct file *file, struct mm_struct *mm)
++{
++      struct task_struct *task;
++      bool ptrace_active = false;
++
++      switch (proc_mem_force_override) {
++      case PROC_MEM_FORCE_NEVER:
++              return false;
++      case PROC_MEM_FORCE_PTRACE:
++              task = get_proc_task(file_inode(file));
++              if (task) {
++                      ptrace_active = READ_ONCE(task->ptrace) &&
++                                      READ_ONCE(task->mm) == mm &&
++                                      READ_ONCE(task->parent) == current;
++                      put_task_struct(task);
++              }
++              return ptrace_active;
++      default:
++              return true;
++      }
++}
++
+ static ssize_t mem_rw(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos, int write)
+ {
+@@ -855,7 +912,9 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
+       if (!mmget_not_zero(mm))
+               goto free;
+-      flags = FOLL_FORCE | (write ? FOLL_WRITE : 0);
++      flags = write ? FOLL_WRITE : 0;
++      if (proc_mem_foll_force(file, mm))
++              flags |= FOLL_FORCE;
+       while (count > 0) {
+               size_t this_len = min_t(size_t, count, PAGE_SIZE);
+diff --git a/security/Kconfig b/security/Kconfig
+index 412e76f1575d0..a93c1a9b7c283 100644
+--- a/security/Kconfig
++++ b/security/Kconfig
+@@ -19,6 +19,38 @@ config SECURITY_DMESG_RESTRICT
+         If you are unsure how to answer this question, answer N.
++choice
++      prompt "Allow /proc/pid/mem access override"
++      default PROC_MEM_ALWAYS_FORCE
++      help
++        Traditionally /proc/pid/mem allows users to override memory
++        permissions for users like ptrace, assuming they have ptrace
++        capability.
++
++        This allows people to limit that - either never override, or
++        require actual active ptrace attachment.
++
++        Defaults to the traditional behavior (for now)
++
++config PROC_MEM_ALWAYS_FORCE
++      bool "Traditional /proc/pid/mem behavior"
++      help
++        This allows /proc/pid/mem accesses to override memory mapping
++        permissions if you have ptrace access rights.
++
++config PROC_MEM_FORCE_PTRACE
++      bool "Require active ptrace() use for access override"
++      help
++        This allows /proc/pid/mem accesses to override memory mapping
++        permissions for active ptracers like gdb.
++
++config PROC_MEM_NO_FORCE
++      bool "Never"
++      help
++        Never override memory mapping permissions
++
++endchoice
++
+ config SECURITY
+       bool "Enable different security models"
+       depends on SYSFS
+-- 
+2.43.0
+
diff --git a/queue-6.10/rcu-tasks-fix-access-non-existent-percpu-rtpcp-varia.patch b/queue-6.10/rcu-tasks-fix-access-non-existent-percpu-rtpcp-varia.patch
new file mode 100644 (file)
index 0000000..0823732
--- /dev/null
@@ -0,0 +1,262 @@
+From b378184a28d14ec00c295e7e5037478cb37354e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 12:45:42 +0800
+Subject: rcu-tasks: Fix access non-existent percpu rtpcp variable in
+ rcu_tasks_need_gpcb()
+
+From: Zqiang <qiang.zhang1211@gmail.com>
+
+[ Upstream commit fd70e9f1d85f5323096ad313ba73f5fe3d15ea41 ]
+
+For kernels built with CONFIG_FORCE_NR_CPUS=y, the nr_cpu_ids is
+defined as NR_CPUS instead of the number of possible cpus, this
+will cause the following system panic:
+
+smpboot: Allowing 4 CPUs, 0 hotplug CPUs
+...
+setup_percpu: NR_CPUS:512 nr_cpumask_bits:512 nr_cpu_ids:512 nr_node_ids:1
+...
+BUG: unable to handle page fault for address: ffffffff9911c8c8
+Oops: 0000 [#1] PREEMPT SMP PTI
+CPU: 0 PID: 15 Comm: rcu_tasks_trace Tainted: G W
+6.6.21 #1 5dc7acf91a5e8e9ac9dcfc35bee0245691283ea6
+RIP: 0010:rcu_tasks_need_gpcb+0x25d/0x2c0
+RSP: 0018:ffffa371c00a3e60 EFLAGS: 00010082
+CR2: ffffffff9911c8c8 CR3: 000000040fa20005 CR4: 00000000001706f0
+Call Trace:
+<TASK>
+? __die+0x23/0x80
+? page_fault_oops+0xa4/0x180
+? exc_page_fault+0x152/0x180
+? asm_exc_page_fault+0x26/0x40
+? rcu_tasks_need_gpcb+0x25d/0x2c0
+? __pfx_rcu_tasks_kthread+0x40/0x40
+rcu_tasks_one_gp+0x69/0x180
+rcu_tasks_kthread+0x94/0xc0
+kthread+0xe8/0x140
+? __pfx_kthread+0x40/0x40
+ret_from_fork+0x34/0x80
+? __pfx_kthread+0x40/0x40
+ret_from_fork_asm+0x1b/0x80
+</TASK>
+
+Considering that there may be holes in the CPU numbers, use the
+maximum possible cpu number, instead of nr_cpu_ids, for configuring
+enqueue and dequeue limits.
+
+[ neeraj.upadhyay: Fix htmldocs build error reported by Stephen Rothwell ]
+
+Closes: https://lore.kernel.org/linux-input/CALMA0xaTSMN+p4xUXkzrtR5r6k7hgoswcaXx7baR_z9r5jjskw@mail.gmail.com/T/#u
+Reported-by: Zhixu Liu <zhixu.liu@gmail.com>
+Signed-off-by: Zqiang <qiang.zhang1211@gmail.com>
+Signed-off-by: Neeraj Upadhyay <neeraj.upadhyay@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rcu/tasks.h | 82 ++++++++++++++++++++++++++++++----------------
+ 1 file changed, 53 insertions(+), 29 deletions(-)
+
+diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
+index ba3440a45b6dd..bc8429ada7a51 100644
+--- a/kernel/rcu/tasks.h
++++ b/kernel/rcu/tasks.h
+@@ -34,6 +34,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
+  * @rtp_blkd_tasks: List of tasks blocked as readers.
+  * @rtp_exit_list: List of tasks in the latter portion of do_exit().
+  * @cpu: CPU number corresponding to this entry.
++ * @index: Index of this CPU in rtpcp_array of the rcu_tasks structure.
+  * @rtpp: Pointer to the rcu_tasks structure.
+  */
+ struct rcu_tasks_percpu {
+@@ -49,6 +50,7 @@ struct rcu_tasks_percpu {
+       struct list_head rtp_blkd_tasks;
+       struct list_head rtp_exit_list;
+       int cpu;
++      int index;
+       struct rcu_tasks *rtpp;
+ };
+@@ -76,6 +78,7 @@ struct rcu_tasks_percpu {
+  * @call_func: This flavor's call_rcu()-equivalent function.
+  * @wait_state: Task state for synchronous grace-period waits (default TASK_UNINTERRUPTIBLE).
+  * @rtpcpu: This flavor's rcu_tasks_percpu structure.
++ * @rtpcp_array: Array of pointers to rcu_tasks_percpu structure of CPUs in cpu_possible_mask.
+  * @percpu_enqueue_shift: Shift down CPU ID this much when enqueuing callbacks.
+  * @percpu_enqueue_lim: Number of per-CPU callback queues in use for enqueuing.
+  * @percpu_dequeue_lim: Number of per-CPU callback queues in use for dequeuing.
+@@ -110,6 +113,7 @@ struct rcu_tasks {
+       call_rcu_func_t call_func;
+       unsigned int wait_state;
+       struct rcu_tasks_percpu __percpu *rtpcpu;
++      struct rcu_tasks_percpu **rtpcp_array;
+       int percpu_enqueue_shift;
+       int percpu_enqueue_lim;
+       int percpu_dequeue_lim;
+@@ -182,6 +186,8 @@ module_param(rcu_task_collapse_lim, int, 0444);
+ static int rcu_task_lazy_lim __read_mostly = 32;
+ module_param(rcu_task_lazy_lim, int, 0444);
++static int rcu_task_cpu_ids;
++
+ /* RCU tasks grace-period state for debugging. */
+ #define RTGS_INIT              0
+ #define RTGS_WAIT_WAIT_CBS     1
+@@ -245,6 +251,8 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
+       int cpu;
+       int lim;
+       int shift;
++      int maxcpu;
++      int index = 0;
+       if (rcu_task_enqueue_lim < 0) {
+               rcu_task_enqueue_lim = 1;
+@@ -254,14 +262,9 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
+       }
+       lim = rcu_task_enqueue_lim;
+-      if (lim > nr_cpu_ids)
+-              lim = nr_cpu_ids;
+-      shift = ilog2(nr_cpu_ids / lim);
+-      if (((nr_cpu_ids - 1) >> shift) >= lim)
+-              shift++;
+-      WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
+-      WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
+-      smp_store_release(&rtp->percpu_enqueue_lim, lim);
++      rtp->rtpcp_array = kcalloc(num_possible_cpus(), sizeof(struct rcu_tasks_percpu *), GFP_KERNEL);
++      BUG_ON(!rtp->rtpcp_array);
++
+       for_each_possible_cpu(cpu) {
+               struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+@@ -273,14 +276,29 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
+               INIT_WORK(&rtpcp->rtp_work, rcu_tasks_invoke_cbs_wq);
+               rtpcp->cpu = cpu;
+               rtpcp->rtpp = rtp;
++              rtpcp->index = index;
++              rtp->rtpcp_array[index] = rtpcp;
++              index++;
+               if (!rtpcp->rtp_blkd_tasks.next)
+                       INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks);
+               if (!rtpcp->rtp_exit_list.next)
+                       INIT_LIST_HEAD(&rtpcp->rtp_exit_list);
++              maxcpu = cpu;
+       }
+-      pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d.\n", rtp->name,
+-                      data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim), rcu_task_cb_adjust);
++      rcu_task_cpu_ids = maxcpu + 1;
++      if (lim > rcu_task_cpu_ids)
++              lim = rcu_task_cpu_ids;
++      shift = ilog2(rcu_task_cpu_ids / lim);
++      if (((rcu_task_cpu_ids - 1) >> shift) >= lim)
++              shift++;
++      WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
++      WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
++      smp_store_release(&rtp->percpu_enqueue_lim, lim);
++
++      pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d rcu_task_cpu_ids=%d.\n",
++                      rtp->name, data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim),
++                      rcu_task_cb_adjust, rcu_task_cpu_ids);
+ }
+ // Compute wakeup time for lazy callback timer.
+@@ -348,7 +366,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
+                       rtpcp->rtp_n_lock_retries = 0;
+               }
+               if (rcu_task_cb_adjust && ++rtpcp->rtp_n_lock_retries > rcu_task_contend_lim &&
+-                  READ_ONCE(rtp->percpu_enqueue_lim) != nr_cpu_ids)
++                  READ_ONCE(rtp->percpu_enqueue_lim) != rcu_task_cpu_ids)
+                       needadjust = true;  // Defer adjustment to avoid deadlock.
+       }
+       // Queuing callbacks before initialization not yet supported.
+@@ -368,10 +386,10 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
+       raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
+       if (unlikely(needadjust)) {
+               raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
+-              if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
++              if (rtp->percpu_enqueue_lim != rcu_task_cpu_ids) {
+                       WRITE_ONCE(rtp->percpu_enqueue_shift, 0);
+-                      WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
+-                      smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
++                      WRITE_ONCE(rtp->percpu_dequeue_lim, rcu_task_cpu_ids);
++                      smp_store_release(&rtp->percpu_enqueue_lim, rcu_task_cpu_ids);
+                       pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
+               }
+               raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
+@@ -444,6 +462,8 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+       dequeue_limit = smp_load_acquire(&rtp->percpu_dequeue_lim);
+       for (cpu = 0; cpu < dequeue_limit; cpu++) {
++              if (!cpu_possible(cpu))
++                      continue;
+               struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+               /* Advance and accelerate any new callbacks. */
+@@ -481,7 +501,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+       if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
+               raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
+               if (rtp->percpu_enqueue_lim > 1) {
+-                      WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(nr_cpu_ids));
++                      WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(rcu_task_cpu_ids));
+                       smp_store_release(&rtp->percpu_enqueue_lim, 1);
+                       rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
+                       gpdone = false;
+@@ -496,7 +516,9 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+                       pr_info("Completing switch %s to CPU-0 callback queuing.\n", rtp->name);
+               }
+               if (rtp->percpu_dequeue_lim == 1) {
+-                      for (cpu = rtp->percpu_dequeue_lim; cpu < nr_cpu_ids; cpu++) {
++                      for (cpu = rtp->percpu_dequeue_lim; cpu < rcu_task_cpu_ids; cpu++) {
++                              if (!cpu_possible(cpu))
++                                      continue;
+                               struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+                               WARN_ON_ONCE(rcu_segcblist_n_cbs(&rtpcp->cblist));
+@@ -511,30 +533,32 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
+ // Advance callbacks and invoke any that are ready.
+ static void rcu_tasks_invoke_cbs(struct rcu_tasks *rtp, struct rcu_tasks_percpu *rtpcp)
+ {
+-      int cpu;
+-      int cpunext;
+       int cpuwq;
+       unsigned long flags;
+       int len;
++      int index;
+       struct rcu_head *rhp;
+       struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl);
+       struct rcu_tasks_percpu *rtpcp_next;
+-      cpu = rtpcp->cpu;
+-      cpunext = cpu * 2 + 1;
+-      if (cpunext < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
+-              rtpcp_next = per_cpu_ptr(rtp->rtpcpu, cpunext);
+-              cpuwq = rcu_cpu_beenfullyonline(cpunext) ? cpunext : WORK_CPU_UNBOUND;
+-              queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
+-              cpunext++;
+-              if (cpunext < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
+-                      rtpcp_next = per_cpu_ptr(rtp->rtpcpu, cpunext);
+-                      cpuwq = rcu_cpu_beenfullyonline(cpunext) ? cpunext : WORK_CPU_UNBOUND;
++      index = rtpcp->index * 2 + 1;
++      if (index < num_possible_cpus()) {
++              rtpcp_next = rtp->rtpcp_array[index];
++              if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
++                      cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND;
+                       queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
++                      index++;
++                      if (index < num_possible_cpus()) {
++                              rtpcp_next = rtp->rtpcp_array[index];
++                              if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
++                                      cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND;
++                                      queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
++                              }
++                      }
+               }
+       }
+-      if (rcu_segcblist_empty(&rtpcp->cblist) || !cpu_possible(cpu))
++      if (rcu_segcblist_empty(&rtpcp->cblist))
+               return;
+       raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
+       rcu_segcblist_advance(&rtpcp->cblist, rcu_seq_current(&rtp->tasks_gp_seq));
+-- 
+2.43.0
+
diff --git a/queue-6.10/rcuscale-provide-clear-error-when-async-specified-wi.patch b/queue-6.10/rcuscale-provide-clear-error-when-async-specified-wi.patch
new file mode 100644 (file)
index 0000000..ae78045
--- /dev/null
@@ -0,0 +1,47 @@
+From 2ab445bbd31de18a7c7497872a84b18f3c597ad0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 17:43:03 -0700
+Subject: rcuscale: Provide clear error when async specified without primitives
+
+From: Paul E. McKenney <paulmck@kernel.org>
+
+[ Upstream commit 11377947b5861fa59bf77c827e1dd7c081842cc9 ]
+
+Currently, if the rcuscale module's async module parameter is specified
+for RCU implementations that do not have async primitives such as RCU
+Tasks Rude (which now lacks a call_rcu_tasks_rude() function), there
+will be a series of splats due to calls to a NULL pointer.  This commit
+therefore warns of this situation, but switches to non-async testing.
+
+Signed-off-by: "Paul E. McKenney" <paulmck@kernel.org>
+Signed-off-by: Neeraj Upadhyay <neeraj.upadhyay@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/rcu/rcuscale.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c
+index 8db4fedaaa1eb..a5806baa1a2a8 100644
+--- a/kernel/rcu/rcuscale.c
++++ b/kernel/rcu/rcuscale.c
+@@ -498,7 +498,7 @@ rcu_scale_writer(void *arg)
+                       schedule_timeout_idle(torture_random(&tr) % writer_holdoff_jiffies + 1);
+               wdp = &wdpp[i];
+               *wdp = ktime_get_mono_fast_ns();
+-              if (gp_async) {
++              if (gp_async && !WARN_ON_ONCE(!cur_ops->async)) {
+ retry:
+                       if (!rhp)
+                               rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
+@@ -554,7 +554,7 @@ rcu_scale_writer(void *arg)
+                       i++;
+               rcu_scale_wait_shutdown();
+       } while (!torture_must_stop());
+-      if (gp_async) {
++      if (gp_async && cur_ops->async) {
+               cur_ops->gp_barrier();
+       }
+       writer_n_durations[me] = i_max + 1;
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch b/queue-6.10/scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch
new file mode 100644 (file)
index 0000000..565d67e
--- /dev/null
@@ -0,0 +1,112 @@
+From b31f13e7acfa95b95e17e607dd658ada07ced947 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jul 2024 14:57:37 -0700
+Subject: scsi: aacraid: Rearrange order of struct aac_srb_unit
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit 6e5860b0ad4934baee8c7a202c02033b2631bb44 ]
+
+struct aac_srb_unit contains struct aac_srb, which contains struct sgmap,
+which ends in a (currently) "fake" (1-element) flexible array.  Converting
+this to a flexible array is needed so that runtime bounds checking won't
+think the array is fixed size (i.e. under CONFIG_FORTIFY_SOURCE=y and/or
+CONFIG_UBSAN_BOUNDS=y), as other parts of aacraid use struct sgmap as a
+flexible array.
+
+It is not legal to have a flexible array in the middle of a structure, so
+it either needs to be split up or rearranged so that it is at the end of
+the structure. Luckily, struct aac_srb_unit, which is exclusively
+consumed/updated by aac_send_safw_bmic_cmd(), does not depend on member
+ordering.
+
+The values set in the on-stack struct aac_srb_unit instance "srbu" by the
+only two callers, aac_issue_safw_bmic_identify() and
+aac_get_safw_ciss_luns(), do not contain anything in srbu.srb.sgmap.sg, and
+they both implicitly initialize srbu.srb.sgmap.count to 0 during
+memset(). For example:
+
+        memset(&srbu, 0, sizeof(struct aac_srb_unit));
+
+        srbcmd = &srbu.srb;
+        srbcmd->flags   = cpu_to_le32(SRB_DataIn);
+        srbcmd->cdb[0]  = CISS_REPORT_PHYSICAL_LUNS;
+        srbcmd->cdb[1]  = 2; /* extended reporting */
+        srbcmd->cdb[8]  = (u8)(datasize >> 8);
+        srbcmd->cdb[9]  = (u8)(datasize);
+
+        rcode = aac_send_safw_bmic_cmd(dev, &srbu, phys_luns, datasize);
+
+During aac_send_safw_bmic_cmd(), a separate srb is mapped into DMA, and has
+srbu.srb copied into it:
+
+        srb = fib_data(fibptr);
+        memcpy(srb, &srbu->srb, sizeof(struct aac_srb));
+
+Only then is srb.sgmap.count written and srb->sg populated:
+
+        srb->count              = cpu_to_le32(xfer_len);
+
+        sg64 = (struct sgmap64 *)&srb->sg;
+        sg64->count             = cpu_to_le32(1);
+        sg64->sg[0].addr[1]     = cpu_to_le32(upper_32_bits(addr));
+        sg64->sg[0].addr[0]     = cpu_to_le32(lower_32_bits(addr));
+        sg64->sg[0].count       = cpu_to_le32(xfer_len);
+
+But this is happening in the DMA memory, not in srbu.srb. An attempt to
+copy the changes back to srbu does happen:
+
+        /*
+         * Copy the updated data for other dumping or other usage if
+         * needed
+         */
+        memcpy(&srbu->srb, srb, sizeof(struct aac_srb));
+
+But this was never correct: the sg64 (3 u32s) overlap of srb.sg (2 u32s)
+always meant that srbu.srb would have held truncated information and any
+attempt to walk srbu.srb.sg.sg based on the value of srbu.srb.sg.count
+would result in attempting to parse past the end of srbu.srb.sg.sg[0] into
+srbu.srb_reply.
+
+After getting a reply from hardware, the reply is copied into
+srbu.srb_reply:
+
+        srb_reply = (struct aac_srb_reply *)fib_data(fibptr);
+        memcpy(&srbu->srb_reply, srb_reply, sizeof(struct aac_srb_reply));
+
+This has always been fixed-size, so there's no issue here. It is worth
+noting that the two callers _never check_ srbu contents -- neither
+srbu.srb nor srbu.srb_reply is examined. (They depend on the mapped
+xfer_buf instead.)
+
+Therefore, the ordering of members in struct aac_srb_unit does not matter,
+and the flexible array member can moved to the end.
+
+(Additionally, the two memcpy()s that update srbu could be entirely
+removed as they are never consumed, but I left that as-is.)
+
+Signed-off-by: Kees Cook <kees@kernel.org>
+Link: https://lore.kernel.org/r/20240711215739.208776-1-kees@kernel.org
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/aacraid/aacraid.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
+index 7d5a155073c62..9b66fa29fb05c 100644
+--- a/drivers/scsi/aacraid/aacraid.h
++++ b/drivers/scsi/aacraid/aacraid.h
+@@ -2029,8 +2029,8 @@ struct aac_srb_reply
+ };
+ struct aac_srb_unit {
+-      struct aac_srb          srb;
+       struct aac_srb_reply    srb_reply;
++      struct aac_srb          srb;
+ };
+ /*
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-lpfc-fix-unsolicited-flogi-kref-imbalance-when-.patch b/queue-6.10/scsi-lpfc-fix-unsolicited-flogi-kref-imbalance-when-.patch
new file mode 100644 (file)
index 0000000..c904459
--- /dev/null
@@ -0,0 +1,197 @@
+From 3dbd3631480ab7895b97913ce3c6af0b195977a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 16:15:09 -0700
+Subject: scsi: lpfc: Fix unsolicited FLOGI kref imbalance when in direct
+ attached topology
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit b5c18c9dd138733c16893613345af44deadcf05e ]
+
+In direct attached topology, certain target vendors that are quick to issue
+FLOGI followed by a cable pull for more than dev_loss_tmo may result in a
+kref imbalance for the remote port ndlp object.
+
+Add an nlp_get when the defer_flogi_acc flag is set.  This is expected to
+balance the nlp_put in the defer_flogi_acc clause in the
+lpfc_issue_els_flogi() routine.  Because we need to retain the ndlp ptr,
+reorganize all of the defer_flogi_acc information into one
+lpfc_defer_flogi_acc struct.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20240726231512.92867-6-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc.h         | 12 ++++++---
+ drivers/scsi/lpfc/lpfc_els.c     | 46 +++++++++++++++++++-------------
+ drivers/scsi/lpfc/lpfc_hbadisc.c | 11 ++++++--
+ 3 files changed, 46 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
+index 7c147d6ea8a8f..e5a9c5a323f8b 100644
+--- a/drivers/scsi/lpfc/lpfc.h
++++ b/drivers/scsi/lpfc/lpfc.h
+@@ -306,6 +306,14 @@ struct lpfc_stats {
+ struct lpfc_hba;
++/* Data structure to keep withheld FLOGI_ACC information */
++struct lpfc_defer_flogi_acc {
++      bool flag;
++      u16 rx_id;
++      u16 ox_id;
++      struct lpfc_nodelist *ndlp;
++
++};
+ #define LPFC_VMID_TIMER   300 /* timer interval in seconds */
+@@ -1430,9 +1438,7 @@ struct lpfc_hba {
+       uint16_t vlan_id;
+       struct list_head fcf_conn_rec_list;
+-      bool defer_flogi_acc_flag;
+-      uint16_t defer_flogi_acc_rx_id;
+-      uint16_t defer_flogi_acc_ox_id;
++      struct lpfc_defer_flogi_acc defer_flogi_acc;
+       spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
+       struct list_head ct_ev_waiters;
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 445cb6c2e80f5..9084976aa77e1 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -1390,7 +1390,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+       phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+       /* Check for a deferred FLOGI ACC condition */
+-      if (phba->defer_flogi_acc_flag) {
++      if (phba->defer_flogi_acc.flag) {
+               /* lookup ndlp for received FLOGI */
+               ndlp = lpfc_findnode_did(vport, 0);
+               if (!ndlp)
+@@ -1404,34 +1404,38 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+               if (phba->sli_rev == LPFC_SLI_REV4) {
+                       bf_set(wqe_ctxt_tag,
+                              &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
+-                             phba->defer_flogi_acc_rx_id);
++                             phba->defer_flogi_acc.rx_id);
+                       bf_set(wqe_rcvoxid,
+                              &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
+-                             phba->defer_flogi_acc_ox_id);
++                             phba->defer_flogi_acc.ox_id);
+               } else {
+                       icmd = &defer_flogi_acc.iocb;
+-                      icmd->ulpContext = phba->defer_flogi_acc_rx_id;
++                      icmd->ulpContext = phba->defer_flogi_acc.rx_id;
+                       icmd->unsli3.rcvsli3.ox_id =
+-                              phba->defer_flogi_acc_ox_id;
++                              phba->defer_flogi_acc.ox_id;
+               }
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                                "3354 Xmit deferred FLOGI ACC: rx_id: x%x,"
+                                " ox_id: x%x, hba_flag x%lx\n",
+-                               phba->defer_flogi_acc_rx_id,
+-                               phba->defer_flogi_acc_ox_id, phba->hba_flag);
++                               phba->defer_flogi_acc.rx_id,
++                               phba->defer_flogi_acc.ox_id, phba->hba_flag);
+               /* Send deferred FLOGI ACC */
+               lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc,
+                                ndlp, NULL);
+-              phba->defer_flogi_acc_flag = false;
+-              vport->fc_myDID = did;
++              phba->defer_flogi_acc.flag = false;
+-              /* Decrement ndlp reference count to indicate the node can be
+-               * released when other references are removed.
++              /* Decrement the held ndlp that was incremented when the
++               * deferred flogi acc flag was set.
+                */
+-              lpfc_nlp_put(ndlp);
++              if (phba->defer_flogi_acc.ndlp) {
++                      lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
++                      phba->defer_flogi_acc.ndlp = NULL;
++              }
++
++              vport->fc_myDID = did;
+       }
+       return 0;
+@@ -8454,9 +8458,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+       /* Defer ACC response until AFTER we issue a FLOGI */
+       if (!test_bit(HBA_FLOGI_ISSUED, &phba->hba_flag)) {
+-              phba->defer_flogi_acc_rx_id = bf_get(wqe_ctxt_tag,
++              phba->defer_flogi_acc.rx_id = bf_get(wqe_ctxt_tag,
+                                                    &wqe->xmit_els_rsp.wqe_com);
+-              phba->defer_flogi_acc_ox_id = bf_get(wqe_rcvoxid,
++              phba->defer_flogi_acc.ox_id = bf_get(wqe_rcvoxid,
+                                                    &wqe->xmit_els_rsp.wqe_com);
+               vport->fc_myDID = did;
+@@ -8464,11 +8468,17 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                                "3344 Deferring FLOGI ACC: rx_id: x%x,"
+                                " ox_id: x%x, hba_flag x%lx\n",
+-                               phba->defer_flogi_acc_rx_id,
+-                               phba->defer_flogi_acc_ox_id, phba->hba_flag);
++                               phba->defer_flogi_acc.rx_id,
++                               phba->defer_flogi_acc.ox_id, phba->hba_flag);
+-              phba->defer_flogi_acc_flag = true;
++              phba->defer_flogi_acc.flag = true;
++              /* This nlp_get is paired with nlp_puts that reset the
++               * defer_flogi_acc.flag back to false.  We need to retain
++               * a kref on the ndlp until the deferred FLOGI ACC is
++               * processed or cancelled.
++               */
++              phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp);
+               return 0;
+       }
+@@ -10504,7 +10514,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+               lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
+               /* retain node if our response is deferred */
+-              if (phba->defer_flogi_acc_flag)
++              if (phba->defer_flogi_acc.flag)
+                       break;
+               if (newnode)
+                       lpfc_disc_state_machine(vport, ndlp, NULL,
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index e74a676b6e153..e553fab869de9 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -1247,7 +1247,14 @@ lpfc_linkdown(struct lpfc_hba *phba)
+       lpfc_scsi_dev_block(phba);
+       offline = pci_channel_offline(phba->pcidev);
+-      phba->defer_flogi_acc_flag = false;
++      /* Decrement the held ndlp if there is a deferred flogi acc */
++      if (phba->defer_flogi_acc.flag) {
++              if (phba->defer_flogi_acc.ndlp) {
++                      lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
++                      phba->defer_flogi_acc.ndlp = NULL;
++              }
++      }
++      phba->defer_flogi_acc.flag = false;
+       /* Clear external loopback plug detected flag */
+       phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+@@ -1369,7 +1376,7 @@ lpfc_linkup_port(struct lpfc_vport *vport)
+               (vport != phba->pport))
+               return;
+-      if (phba->defer_flogi_acc_flag) {
++      if (phba->defer_flogi_acc.flag) {
+               clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag);
+               clear_bit(FC_RSCN_MODE, &vport->fc_flag);
+               clear_bit(FC_NLP_MORE, &vport->fc_flag);
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch b/queue-6.10/scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch
new file mode 100644 (file)
index 0000000..215bb76
--- /dev/null
@@ -0,0 +1,113 @@
+From 9701af2014055cc8084b8787a1e083663b554e87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 16:15:10 -0700
+Subject: scsi: lpfc: Update PRLO handling in direct attached topology
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 1f0f7679ad8942f810b0f19ee9cf098c3502d66a ]
+
+A kref imbalance occurs when handling an unsolicited PRLO in direct
+attached topology.
+
+Rework PRLO rcv handling when in MAPPED state.  Save the state that we were
+handling a PRLO by setting nlp_last_elscmd to ELS_CMD_PRLO.  Then in the
+lpfc_cmpl_els_logo_acc() completion routine, manually restart discovery.
+By issuing the PLOGI, which nlp_gets, before nlp_put at the end of the
+lpfc_cmpl_els_logo_acc() routine, we are saving us from a final nlp_put.
+And, we are still allowing the unreg_rpi to happen.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20240726231512.92867-7-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_els.c       | 27 ++++++++++++++++-----------
+ drivers/scsi/lpfc/lpfc_nportdisc.c | 22 ++++++++++++++++++++--
+ 2 files changed, 36 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
+index 9084976aa77e1..9c8a6d2a29049 100644
+--- a/drivers/scsi/lpfc/lpfc_els.c
++++ b/drivers/scsi/lpfc/lpfc_els.c
+@@ -5244,9 +5244,10 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+       /* ACC to LOGO completes to NPort <nlp_DID> */
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                        "0109 ACC to LOGO completes to NPort x%x refcnt %d "
+-                       "Data: x%x x%x x%x\n",
+-                       ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag,
+-                       ndlp->nlp_state, ndlp->nlp_rpi);
++                       "last els x%x Data: x%x x%x x%x\n",
++                       ndlp->nlp_DID, kref_read(&ndlp->kref),
++                       ndlp->nlp_last_elscmd, ndlp->nlp_flag, ndlp->nlp_state,
++                       ndlp->nlp_rpi);
+       /* This clause allows the LOGO ACC to complete and free resources
+        * for the Fabric Domain Controller.  It does deliberately skip
+@@ -5258,18 +5259,22 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+               goto out;
+       if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+-              /* If PLOGI is being retried, PLOGI completion will cleanup the
+-               * node. The NLP_NPR_2B_DISC flag needs to be retained to make
+-               * progress on nodes discovered from last RSCN.
+-               */
+-              if ((ndlp->nlp_flag & NLP_DELAY_TMO) &&
+-                  (ndlp->nlp_last_elscmd == ELS_CMD_PLOGI))
+-                      goto out;
+-
+               if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
+                       lpfc_unreg_rpi(vport, ndlp);
++              /* If came from PRLO, then PRLO_ACC is done.
++               * Start rediscovery now.
++               */
++              if (ndlp->nlp_last_elscmd == ELS_CMD_PRLO) {
++                      spin_lock_irq(&ndlp->lock);
++                      ndlp->nlp_flag |= NLP_NPR_2B_DISC;
++                      spin_unlock_irq(&ndlp->lock);
++                      ndlp->nlp_prev_state = ndlp->nlp_state;
++                      lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
++                      lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
++              }
+       }
++
+  out:
+       /*
+        * The driver received a LOGO from the rport and has ACK'd it.
+diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
+index f6a53446e57f9..4574716c8764f 100644
+--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
+@@ -2652,8 +2652,26 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+       /* flush the target */
+       lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT);
+-      /* Treat like rcv logo */
+-      lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
++      /* Send PRLO_ACC */
++      spin_lock_irq(&ndlp->lock);
++      ndlp->nlp_flag |= NLP_LOGO_ACC;
++      spin_unlock_irq(&ndlp->lock);
++      lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
++
++      /* Save ELS_CMD_PRLO as the last elscmd and then set to NPR.
++       * lpfc_cmpl_els_logo_acc is expected to restart discovery.
++       */
++      ndlp->nlp_last_elscmd = ELS_CMD_PRLO;
++      ndlp->nlp_prev_state = ndlp->nlp_state;
++
++      lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_ELS | LOG_DISCOVERY,
++                       "3422 DID x%06x nflag x%x lastels x%x ref cnt %u\n",
++                       ndlp->nlp_DID, ndlp->nlp_flag,
++                       ndlp->nlp_last_elscmd,
++                       kref_read(&ndlp->kref));
++
++      lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
++
+       return ndlp->nlp_state;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-lpfc-validate-hdwq-pointers-before-dereferencin.patch b/queue-6.10/scsi-lpfc-validate-hdwq-pointers-before-dereferencin.patch
new file mode 100644 (file)
index 0000000..a91ad61
--- /dev/null
@@ -0,0 +1,94 @@
+From 01812561c7b8585ca74274cf9759fcabcb49351f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 26 Jul 2024 16:15:07 -0700
+Subject: scsi: lpfc: Validate hdwq pointers before dereferencing in
+ reset/errata paths
+
+From: Justin Tee <justin.tee@broadcom.com>
+
+[ Upstream commit 2be1d4f11944cd6283cb97268b3e17c4424945ca ]
+
+When the HBA is undergoing a reset or is handling an errata event, NULL ptr
+dereference crashes may occur in routines such as
+lpfc_sli_flush_io_rings(), lpfc_dev_loss_tmo_callbk(), or
+lpfc_abort_handler().
+
+Add NULL ptr checks before dereferencing hdwq pointers that may have been
+freed due to operations colliding with a reset or errata event handler.
+
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Link: https://lore.kernel.org/r/20240726231512.92867-4-justintee8345@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_hbadisc.c |  3 ++-
+ drivers/scsi/lpfc/lpfc_scsi.c    | 13 +++++++++++--
+ drivers/scsi/lpfc/lpfc_sli.c     | 11 +++++++++++
+ 3 files changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
+index 13b08c85440fe..e74a676b6e153 100644
+--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
+@@ -175,7 +175,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+                        ndlp->nlp_state, ndlp->fc4_xpt_flags);
+       /* Don't schedule a worker thread event if the vport is going down. */
+-      if (test_bit(FC_UNLOADING, &vport->load_flag)) {
++      if (test_bit(FC_UNLOADING, &vport->load_flag) ||
++          !test_bit(HBA_SETUP, &phba->hba_flag)) {
+               spin_lock_irqsave(&ndlp->lock, iflags);
+               ndlp->rport = NULL;
+diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
+index 9f0b59672e191..0eaede8275dac 100644
+--- a/drivers/scsi/lpfc/lpfc_scsi.c
++++ b/drivers/scsi/lpfc/lpfc_scsi.c
+@@ -5555,11 +5555,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
+       iocb = &lpfc_cmd->cur_iocbq;
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+-              pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring;
+-              if (!pring_s4) {
++              /* if the io_wq & pring are gone, the port was reset. */
++              if (!phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq ||
++                  !phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring) {
++                      lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
++                                       "2877 SCSI Layer I/O Abort Request "
++                                       "IO CMPL Status x%x ID %d LUN %llu "
++                                       "HBA_SETUP %d\n", FAILED,
++                                       cmnd->device->id,
++                                       (u64)cmnd->device->lun,
++                                       test_bit(HBA_SETUP, &phba->hba_flag));
+                       ret = FAILED;
+                       goto out_unlock_hba;
+               }
++              pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring;
+               spin_lock(&pring_s4->ring_lock);
+       }
+       /* the command is in process of being cancelled */
+diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
+index 3e55d5edd60ab..c6fcaeeb52945 100644
+--- a/drivers/scsi/lpfc/lpfc_sli.c
++++ b/drivers/scsi/lpfc/lpfc_sli.c
+@@ -4687,6 +4687,17 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba)
+       /* Look on all the FCP Rings for the iotag */
+       if (phba->sli_rev >= LPFC_SLI_REV4) {
+               for (i = 0; i < phba->cfg_hdw_queue; i++) {
++                      if (!phba->sli4_hba.hdwq ||
++                          !phba->sli4_hba.hdwq[i].io_wq) {
++                              lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
++                                              "7777 hdwq's deleted %lx "
++                                              "%lx %x %x\n",
++                                              phba->pport->load_flag,
++                                              phba->hba_flag,
++                                              phba->link_state,
++                                              phba->sli.sli_flag);
++                              return;
++                      }
+                       pring = phba->sli4_hba.hdwq[i].io_wq->pring;
+                       spin_lock_irq(&pring->ring_lock);
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch b/queue-6.10/scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch
new file mode 100644 (file)
index 0000000..635f61f
--- /dev/null
@@ -0,0 +1,50 @@
+From c961291e892285b949af10d6a243645cc08d45af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 13:36:28 +1000
+Subject: scsi: NCR5380: Initialize buffer for MSG IN and STATUS transfers
+
+From: Finn Thain <fthain@linux-m68k.org>
+
+[ Upstream commit 1c71065df2df693d208dd32758171c1dece66341 ]
+
+Following an incomplete transfer in MSG IN phase, the driver would not
+notice the problem and would make use of invalid data. Initialize 'tmp'
+appropriately and bail out if no message was received. For STATUS phase,
+preserve the existing status code unless a new value was transferred.
+
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@linux-m68k.org>
+Link: https://lore.kernel.org/r/52e02a8812ae1a2d810d7f9f7fd800c3ccc320c4.1723001788.git.fthain@linux-m68k.org
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/NCR5380.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
+index 00e245173320c..4fcb73b727aa5 100644
+--- a/drivers/scsi/NCR5380.c
++++ b/drivers/scsi/NCR5380.c
+@@ -1807,8 +1807,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
+                               return;
+                       case PHASE_MSGIN:
+                               len = 1;
++                              tmp = 0xff;
+                               data = &tmp;
+                               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
++                              if (tmp == 0xff)
++                                      break;
+                               ncmd->message = tmp;
+                               switch (tmp) {
+@@ -1996,6 +1999,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
+                               break;
+                       case PHASE_STATIN:
+                               len = 1;
++                              tmp = ncmd->status;
+                               data = &tmp;
+                               NCR5380_transfer_pio(instance, &phase, &len, &data, 0);
+                               ncmd->status = tmp;
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-smartpqi-add-new-controller-pci-ids.patch b/queue-6.10/scsi-smartpqi-add-new-controller-pci-ids.patch
new file mode 100644 (file)
index 0000000..61434e4
--- /dev/null
@@ -0,0 +1,193 @@
+From 587e358a76090f7e303c17db3e661ef9472b7e00 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jul 2024 14:47:00 -0500
+Subject: scsi: smartpqi: Add new controller PCI IDs
+
+From: David Strahan <David.Strahan@microchip.com>
+
+[ Upstream commit 0e21e73384d324f75ea16f3d622cfc433fa6209b ]
+
+All PCI ID entries in hex.
+
+Add new inagile PCI IDs:
+                                             VID  / DID  / SVID / SDID
+                                             ----   ----   ----   ----
+            SMART-HBA 8242-24i               9005 / 028f / 1ff9 / 0045
+            RAID 8236-16i                    9005 / 028f / 1ff9 / 0046
+            RAID 8240-24i                    9005 / 028f / 1ff9 / 0047
+            SMART-HBA 8238-16i               9005 / 028f / 1ff9 / 0048
+            PM8222-SHBA                      9005 / 028f / 1ff9 / 004a
+            RAID PM8204-2GB                  9005 / 028f / 1ff9 / 004b
+            RAID PM8204-4GB                  9005 / 028f / 1ff9 / 004c
+            PM8222-HBA                       9005 / 028f / 1ff9 / 004f
+            MT0804M6R                        9005 / 028f / 1ff9 / 0051
+            MT0801M6E                        9005 / 028f / 1ff9 / 0052
+            MT0808M6R                        9005 / 028f / 1ff9 / 0053
+            MT0800M6H                        9005 / 028f / 1ff9 / 0054
+            RS0800M5H24i                     9005 / 028f / 1ff9 / 006b
+            RS0800M5E8i                      9005 / 028f / 1ff9 / 006c
+            RS0800M5H8i                      9005 / 028f / 1ff9 / 006d
+            RS0804M5R16i                     9005 / 028f / 1ff9 / 006f
+            RS0800M5E24i                     9005 / 028f / 1ff9 / 0070
+            RS0800M5H16i                     9005 / 028f / 1ff9 / 0071
+            RS0800M5E16i                     9005 / 028f / 1ff9 / 0072
+            RT0800M7E                        9005 / 028f / 1ff9 / 0086
+            RT0800M7H                        9005 / 028f / 1ff9 / 0087
+            RT0804M7R                        9005 / 028f / 1ff9 / 0088
+            RT0808M7R                        9005 / 028f / 1ff9 / 0089
+            RT1608M6R16i                     9005 / 028f / 1ff9 / 00a1
+
+Add new h3c pci_id:
+                                             VID  / DID  / SVID / SDID
+                                             ----   ----   ----   ----
+            UN RAID P4408-Mr-2               9005 / 028f / 193d / 1110
+
+Add new powerleader pci ids:
+                                             VID  / DID  / SVID / SDID
+                                             ----   ----   ----   ----
+            PL SmartROC PM8204               9005 / 028f / 1f3a / 0104
+
+Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
+Reviewed-by: Scott Teel <scott.teel@microchip.com>
+Reviewed-by: Mike McGowen <mike.mcgowen@microchip.com>
+Signed-off-by: David Strahan <David.Strahan@microchip.com>
+Signed-off-by: Don Brace <don.brace@microchip.com>
+Link: https://lore.kernel.org/r/20240711194704.982400-2-don.brace@microchip.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/smartpqi/smartpqi_init.c | 104 ++++++++++++++++++++++++++
+ 1 file changed, 104 insertions(+)
+
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index c1524fb334eb5..02d16fddd3123 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -9456,6 +9456,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x193d, 0x110b)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x193d, 0x1110)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x193d, 0x8460)
+@@ -9572,6 +9576,14 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x1bd4, 0x0089)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x00a1)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1f3a, 0x0104)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x19e5, 0xd227)
+@@ -10164,6 +10176,98 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x1137, 0x02fa)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0045)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0046)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0047)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0048)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x004a)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x004b)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x004c)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x004f)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0051)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0052)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0053)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0054)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x006b)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x006c)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x006d)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x006f)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0070)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0071)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0072)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0086)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0087)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0088)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x0089)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                               0x1e93, 0x1000)
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-smartpqi-add-new-controller-pci-ids.patch-21617 b/queue-6.10/scsi-smartpqi-add-new-controller-pci-ids.patch-21617
new file mode 100644 (file)
index 0000000..e95ba2a
--- /dev/null
@@ -0,0 +1,99 @@
+From b295b8bfb64bd628dd21f6533735cc3a918cc716 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 13:54:58 -0500
+Subject: scsi: smartpqi: add new controller PCI IDs
+
+From: David Strahan <David.Strahan@microchip.com>
+
+[ Upstream commit dbc39b84540f746cc814e69b21e53e6d3e12329a ]
+
+All PCI ID entries in Hex.
+
+Add new cisco pci ids:
+                                             VID  / DID  / SVID / SDID
+                                             ----   ----   ----   ----
+                                             9005   028f   1137   02fe
+                                             9005   028f   1137   02ff
+                                             9005   028f   1137   0300
+
+Add new h3c pci ids:
+                                             VID  / DID  / SVID / SDID
+                                             ----   ----   ----   ----
+                                             9005   028f   193d   0462
+                                             9005   028f   193d   8462
+
+Add new ieit pci ids:
+                                             VID  / DID  / SVID / SDID
+                                             ----   ----   ----   ----
+                                             9005   028f   1ff9   00a3
+
+Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
+Reviewed-by: Mike McGowen <mike.mcgowen@microchip.com>
+Signed-off-by: David Strahan <David.Strahan@microchip.com>
+Signed-off-by: Don Brace <don.brace@microchip.com>
+Link: https://lore.kernel.org/r/20240827185501.692804-5-don.brace@microchip.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/smartpqi/smartpqi_init.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index a4719af88718e..4230714e5f3a1 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -9428,6 +9428,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x152d, 0x8a37)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x193d, 0x0462)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x193d, 0x1104)
+@@ -9468,6 +9472,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x193d, 0x8461)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x193d, 0x8462)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x193d, 0xc460)
+@@ -10176,6 +10184,18 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x1137, 0x02fa)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1137, 0x02fe)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1137, 0x02ff)
++      },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1137, 0x0300)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x1ff9, 0x0045)
+@@ -10352,6 +10372,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              0x1f51, 0x1045)
+       },
++      {
++              PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
++                             0x1ff9, 0x00a3)
++      },
+       {
+               PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+                              PCI_ANY_ID, PCI_ANY_ID)
+-- 
+2.43.0
+
diff --git a/queue-6.10/scsi-smartpqi-correct-stream-detection.patch b/queue-6.10/scsi-smartpqi-correct-stream-detection.patch
new file mode 100644 (file)
index 0000000..ad6e594
--- /dev/null
@@ -0,0 +1,50 @@
+From d78a23acacd8b11bfd391e990956a7b2826c9920 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 13:54:56 -0500
+Subject: scsi: smartpqi: correct stream detection
+
+From: Mahesh Rajashekhara <mahesh.rajashekhara@microchip.com>
+
+[ Upstream commit 4c76114932d1d6fad2e72823e7898a3c960cf2a7 ]
+
+Correct stream detection by initializing the structure
+pqi_scsi_dev_raid_map_data to 0s.
+
+When the OS issues SCSI READ commands, the driver erroneously considers
+them as SCSI WRITES. If they are identified as sequential IOs, the driver
+then submits those requests via the RAID path instead of the AIO path.
+
+The 'is_write' flag might be set for SCSI READ commands also.  The driver
+may interpret SCSI READ commands as SCSI WRITE commands, resulting in IOs
+being submitted through the RAID path.
+
+Note: This does not cause data corruption.
+
+Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
+Reviewed-by: Scott Teel <scott.teel@microchip.com>
+Reviewed-by: Mike McGowen <mike.mcgowen@microchip.com>
+Signed-off-by: Mahesh Rajashekhara <mahesh.rajashekhara@microchip.com>
+Signed-off-by: Don Brace <don.brace@microchip.com>
+Link: https://lore.kernel.org/r/20240827185501.692804-3-don.brace@microchip.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/smartpqi/smartpqi_init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
+index 02d16fddd3123..a4719af88718e 100644
+--- a/drivers/scsi/smartpqi/smartpqi_init.c
++++ b/drivers/scsi/smartpqi/smartpqi_init.c
+@@ -5917,7 +5917,7 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info,
+       int rc;
+       struct pqi_scsi_dev *device;
+       struct pqi_stream_data *pqi_stream_data;
+-      struct pqi_scsi_dev_raid_map_data rmd;
++      struct pqi_scsi_dev_raid_map_data rmd = { 0 };
+       if (!ctrl_info->enable_stream_detection)
+               return false;
+-- 
+2.43.0
+
diff --git a/queue-6.10/selftests-nolibc-avoid-passing-null-to-printf-s.patch b/queue-6.10/selftests-nolibc-avoid-passing-null-to-printf-s.patch
new file mode 100644 (file)
index 0000000..110caf2
--- /dev/null
@@ -0,0 +1,52 @@
+From 9e04b8ef13ebdbc3cfa8f07a6f070c44a7797b08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 23:51:44 +0200
+Subject: selftests/nolibc: avoid passing NULL to printf("%s")
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit f1a58f61d88642ae1e6e97e9d72d73bc70a93cb8 ]
+
+Clang on higher optimization levels detects that NULL is passed to
+printf("%s") and warns about it.
+While printf() from nolibc gracefully handles that NULL,
+it is undefined behavior as per POSIX, so the warning is reasonable.
+Avoid the warning by transforming NULL into a non-NULL placeholder.
+
+Reviewed-by: Shuah Khan <skhan@linuxfoundation.org>
+Acked-by: Willy Tarreau <w@1wt.eu>
+Link: https://lore.kernel.org/r/20240807-nolibc-llvm-v2-8-c20f2f5fc7c2@weissschuh.net
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/nolibc/nolibc-test.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
+index 994477ee87bef..4bd8360d54225 100644
+--- a/tools/testing/selftests/nolibc/nolibc-test.c
++++ b/tools/testing/selftests/nolibc/nolibc-test.c
+@@ -534,7 +534,7 @@ int expect_strzr(const char *expr, int llen)
+ {
+       int ret = 0;
+-      llen += printf(" = <%s> ", expr);
++      llen += printf(" = <%s> ", expr ? expr : "(null)");
+       if (expr) {
+               ret = 1;
+               result(llen, FAIL);
+@@ -553,7 +553,7 @@ int expect_strnz(const char *expr, int llen)
+ {
+       int ret = 0;
+-      llen += printf(" = <%s> ", expr);
++      llen += printf(" = <%s> ", expr ? expr : "(null)");
+       if (!expr) {
+               ret = 1;
+               result(llen, FAIL);
+-- 
+2.43.0
+
index 4ce0d1cd5b16e8d1a8b99804700e8308643e01f7..0f5c3813a1e231513d0610a971005d2e11b816c3 100644 (file)
@@ -68,3 +68,191 @@ cifs-do-not-convert-delimiter-when-parsing-nfs-style.patch
 tools-rtla-fix-installation-from-out-of-tree-build.patch
 alsa-gus-fix-some-error-handling-paths-related-to-ge.patch
 alsa-hda-conexant-fix-conflicting-quirk-for-system76.patch
+wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch
+wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch
+wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch
+crypto-x86-sha256-add-parentheses-around-macros-sing.patch
+crypto-octeontx-fix-authenc-setkey.patch
+crypto-octeontx2-fix-authenc-setkey.patch
+ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch
+wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch
+wifi-iwlwifi-mvm-drop-wrong-sta-selection-in-tx.patch
+wifi-cfg80211-set-correct-chandef-when-starting-cac.patch
+net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch
+net-hisilicon-hip04-fix-of-node-leak-in-probe.patch
+net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch
+net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch
+acpi-pad-fix-crash-in-exit_round_robin.patch
+acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch
+acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch
+fs-inode-prevent-dump_mapping-accessing-invalid-dent.patch
+e1000e-avoid-failing-the-system-during-pm_suspend.patch
+acpi-resource-skip-irq-override-on-asus-vivobook-go-.patch
+wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch
+net-sched-consistently-use-rcu_replace_pointer-in-ta.patch
+bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch
+bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch
+acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch
+acpi-cppc-add-support-for-setting-epp-register-in-ff.patch
+blk_iocost-fix-more-out-of-bound-shifts.patch
+wifi-ath12k-fix-array-out-of-bound-access-in-soc-sta.patch
+wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch
+wifi-rtw88-select-want_dev_coredump.patch
+acpi-ec-do-not-release-locks-during-operation-region.patch
+acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch
+tipc-guard-against-string-buffer-overrun.patch
+net-mvpp2-increase-size-of-queue_name-buffer.patch
+bnxt_en-extend-maximum-length-of-version-string-by-1.patch
+ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch
+wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch
+ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch
+nvme-keyring-restrict-match-length-for-version-1-ide.patch
+nvme-tcp-sanitize-tls-key-handling.patch
+nvme-tcp-check-for-invalidated-or-revoked-key.patch
+net-atlantic-avoid-warning-about-potential-string-tr.patch
+crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch
+netpoll-ensure-clean-state-on-setup-failures.patch
+tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch
+wifi-iwlwifi-mvm-use-correct-key-iteration.patch
+wifi-iwlwifi-allow-only-cn-mcc-from-wrdd.patch
+wifi-iwlwifi-mvm-avoid-null-pointer-dereference.patch
+wifi-mac80211-fix-rcu-list-iterations.patch
+acpica-iasl-handle-empty-connection_node.patch
+proc-add-config-param-to-block-forcing-mem-writes.patch
+drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch
+can-netlink-avoid-call-to-do_set_data_bittiming-call.patch
+netdev-genl-set-extack-and-fix-error-on-napi-get.patch
+block-fix-integer-overflow-in-blksecdiscard.patch
+arm64-trans_pgd-mark-ptes-entries-as-valid-to-avoid-.patch
+net-phy-check-for-read-errors-in-siocgmiireg.patch
+wifi-rtw89-avoid-reading-out-of-bounds-when-loading-.patch
+x86-bugs-add-missing-no_ssb-flag.patch
+x86-bugs-fix-handling-when-srso-mitigation-is-disabl.patch
+net-napi-prevent-overflow-of-napi_defer_hard_irqs.patch
+crypto-hisilicon-fix-missed-error-branch.patch
+wifi-mt76-mt7915-add-dummy-hw-offload-of-ieee-802.11.patch
+wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch
+wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch
+netfs-cancel-dirty-folios-that-have-no-storage-desti.patch
+nfp-use-irqf_no_autoen-flag-in-request_irq.patch
+alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
+x86-ioapic-handle-allocation-failures-gracefully.patch
+x86-apic-remove-logical-destination-mode-for-64-bit.patch
+alsa-usb-audio-support-multiple-control-interfaces.patch
+alsa-usb-audio-define-macros-for-quirk-table-entries.patch
+alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
+alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch
+alsa-usb-audio-add-mixer-quirk-for-rme-digiface-usb.patch
+alsa-usb-audio-add-logitech-audio-profile-quirk.patch
+asoc-codecs-wsa883x-handle-reading-version-failure.patch
+alsa-control-take-power_ref-lock-primarily.patch
+tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch
+x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch
+x86-pkeys-restore-altstack-access-in-sigreturn.patch
+x86-kexec-add-efi-config-table-identity-mapping-for-.patch
+x86-mm-ident_map-use-gbpages-only-where-full-gb-page.patch
+alsa-asihpi-fix-potential-oob-array-access.patch
+alsa-hdsp-break-infinite-midi-input-flush-loop.patch
+tools-nolibc-powerpc-limit-stack-protector-workaroun.patch
+selftests-nolibc-avoid-passing-null-to-printf-s.patch
+x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch
+asoc-intel-boards-always-check-the-result-of-acpi_de.patch
+rcu-tasks-fix-access-non-existent-percpu-rtpcp-varia.patch
+hwmon-nct6775-add-g15cf-to-asus-wmi-monitoring-list.patch
+fbdev-efifb-register-sysfs-groups-through-driver-cor.patch
+fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch
+pmdomain-core-don-t-hold-the-genpd-lock-when-calling.patch
+coredump-standartize-and-fix-logging.patch
+rcuscale-provide-clear-error-when-async-specified-wi.patch
+power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch
+iommu-arm-smmu-v3-match-stall-behaviour-for-s2.patch
+iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch
+iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch
+iommu-vt-d-unconditionally-flush-device-tlb-for-pasi.patch
+iommu-arm-smmu-v3-do-not-use-devm-for-the-cd-table-a.patch
+cgroup-disallow-mounting-v1-hierarchies-without-cont.patch
+drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch
+drm-amd-display-pass-non-null-to-dcn20_validate_appl.patch
+drm-amd-display-check-null-pointers-before-using-the.patch
+drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch
+drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch
+drm-amd-display-add-null-check-for-head_pipe-in-dcn2.patch
+drm-amd-display-add-null-check-for-head_pipe-in-dcn3.patch
+drm-amd-display-add-null-check-for-clk_mgr-and-clk_m.patch
+drm-amd-display-add-null-check-for-clk_mgr-in-dcn32_.patch
+drm-xe-hdcp-check-gsc-structure-validity.patch
+drm-amd-display-add-null-check-for-top_pipe_to_progr.patch
+drm-amd-display-use-gpuvm_min_page_size_kbytes-for-d.patch
+ata-pata_serverworks-do-not-use-the-term-blacklist.patch
+ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch
+scsi-smartpqi-add-new-controller-pci-ids.patch
+hid-ignore-battery-for-all-elan-i2c-hid-devices.patch
+drm-amd-display-handle-null-stream_status-in-planes_.patch
+drm-amd-display-add-null-check-for-function-pointer-.patch
+drm-amd-display-add-null-check-for-function-pointer-.patch-29584
+drm-amd-display-check-null-pointers-before-using-dc-.patch
+drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch
+drm-amd-display-fix-double-free-issue-during-amdgpu-.patch
+drm-amdgpu-add-list-empty-check-to-avoid-null-pointe.patch
+jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch
+jfs-fix-uaf-in-dbfreebits.patch
+jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch
+scsi-smartpqi-correct-stream-detection.patch
+scsi-smartpqi-add-new-controller-pci-ids.patch-21617
+drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch
+jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch
+drm-amdgpu-add-raven1-gfxoff-quirk.patch
+drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch
+drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch
+hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch
+platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch
+platform-x86-amd-pmf-add-quirk-for-tuf-gaming-a14.patch
+drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch
+drm-amd-display-check-null-initialized-variables.patch
+drm-amd-display-check-phantom_stream-before-it-is-us.patch
+drm-amd-display-check-stream-before-comparing-them.patch
+drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch
+drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch
+drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch
+drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch
+drm-amdgpu-gfx9-properly-handle-error-ints-on-all-pi.patch
+drm-amd-display-avoid-overflow-assignment-in-link_dp.patch
+drm-amd-display-initialize-get_bytes_per_element-s-d.patch
+drm-printer-allow-null-data-in-devcoredump-printer.patch
+perf-x86-avoid-missing-caller-address-in-stack-trace.patch
+scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch
+scsi-lpfc-validate-hdwq-pointers-before-dereferencin.patch
+scsi-lpfc-fix-unsolicited-flogi-kref-imbalance-when-.patch
+scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch
+drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch
+drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch-12177
+perf-fix-event_function_call-locking.patch
+scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch
+drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch
+drm-amdgpu-block-mmr_read-ioctl-in-reset.patch
+drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch
+drm-amdgpu-gfx11-enter-safe-mode-before-touching-cp_.patch
+drm-xe-use-topology-to-determine-page-fault-queue-si.patch
+drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch
+drm-amdkfd-check-int-source-id-for-utcl2-poison-even.patch
+drm-xe-drop-warn-on-xe_guc_pc_gucrc_disable-in-guc-p.patch
+of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch
+powerpc-pseries-use-correct-data-types-from-pseries_.patch
+ovl-fsync-after-metadata-copy-up.patch
+drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch
+drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch
+platform-x86-lenovo-ymc-ignore-the-0x0-state.patch
+tools-hv-add-memory-allocation-check-in-hv_fcopy_sta.patch
+hid-i2c-hid-ensure-various-commands-do-not-interfere.patch
+ksmbd-add-refcnt-to-ksmbd_conn-struct.patch
+platform-mellanox-mlxbf-pmc-fix-lockdep-warning.patch
+platform-x86-x86-android-tablets-adjust-xiaomi-pad-2.patch
+ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch
+bpf-make-the-pointer-returned-by-iter-next-method-va.patch
+ext4-ext4_search_dir-should-return-a-proper-error.patch
+ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch
+ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch
+bpftool-fix-undefined-behavior-caused-by-shifting-in.patch
+iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch
+bpftool-fix-undefined-behavior-in-qsort-null-0.patch
+bpf-fix-a-sdiv-overflow-issue.patch
diff --git a/queue-6.10/tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch b/queue-6.10/tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch
new file mode 100644 (file)
index 0000000..a718f3e
--- /dev/null
@@ -0,0 +1,82 @@
+From 45ce775ff434bd03718f2f9f38625b2cb0b5c6f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Aug 2024 08:11:52 +0800
+Subject: tcp: avoid reusing FIN_WAIT2 when trying to find port in connect()
+ process
+
+From: Jason Xing <kernelxing@tencent.com>
+
+[ Upstream commit 0d9e5df4a257afc3a471a82961ace9a22b88295a ]
+
+We found that one close-wait socket was reset by the other side
+due to a new connection reusing the same port which is beyond our
+expectation, so we have to investigate the underlying reason.
+
+The following experiment is conducted in the test environment. We
+limit the port range from 40000 to 40010 and delay the time to close()
+after receiving a fin from the active close side, which can help us
+easily reproduce like what happened in production.
+
+Here are three connections captured by tcpdump:
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [S], seq 2965525191
+127.0.0.1.9999 > 127.0.0.1.40002: Flags [S.], seq 2769915070
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [.], ack 1
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [F.], seq 1, ack 1
+// a few seconds later, within 60 seconds
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [S], seq 2965590730
+127.0.0.1.9999 > 127.0.0.1.40002: Flags [.], ack 2
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [R], seq 2965525193
+// later, very quickly
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [S], seq 2965590730
+127.0.0.1.9999 > 127.0.0.1.40002: Flags [S.], seq 3120990805
+127.0.0.1.40002 > 127.0.0.1.9999: Flags [.], ack 1
+
+As we can see, the first flow is reset because:
+1) client starts a new connection, I mean, the second one
+2) client tries to find a suitable port which is a timewait socket
+   (its state is timewait, substate is fin_wait2)
+3) client occupies that timewait port to send a SYN
+4) server finds a corresponding close-wait socket in ehash table,
+   then replies with a challenge ack
+5) client sends an RST to terminate this old close-wait socket.
+
+I don't think the port selection algo can choose a FIN_WAIT2 socket
+when we turn on tcp_tw_reuse because on the server side there
+remain unread data. In some cases, if one side haven't call close() yet,
+we should not consider it as expendable and treat it at will.
+
+Even though, sometimes, the server isn't able to call close() as soon
+as possible like what we expect, it can not be terminated easily,
+especially due to a second unrelated connection happening.
+
+After this patch, we can see the expected failure if we start a
+connection when all the ports are occupied in fin_wait2 state:
+"Ncat: Cannot assign requested address."
+
+Reported-by: Jade Dong <jadedong@tencent.com>
+Signed-off-by: Jason Xing <kernelxing@tencent.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20240823001152.31004-1-kerneljasonxing@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_ipv4.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
+index da0f502553991..7874b3718bc3c 100644
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -118,6 +118,9 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
+       struct tcp_sock *tp = tcp_sk(sk);
+       int ts_recent_stamp;
++      if (tw->tw_substate == TCP_FIN_WAIT2)
++              reuse = 0;
++
+       if (reuse == 2) {
+               /* Still does not detect *everything* that goes through
+                * lo, since we require a loopback src or dst address
+-- 
+2.43.0
+
diff --git a/queue-6.10/tipc-guard-against-string-buffer-overrun.patch b/queue-6.10/tipc-guard-against-string-buffer-overrun.patch
new file mode 100644 (file)
index 0000000..b548291
--- /dev/null
@@ -0,0 +1,53 @@
+From 1d04e383af2fa259bc3cfa1ae29b18b9a186144e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Aug 2024 19:35:37 +0100
+Subject: tipc: guard against string buffer overrun
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 6555a2a9212be6983d2319d65276484f7c5f431a ]
+
+Smatch reports that copying media_name and if_name to name_parts may
+overwrite the destination.
+
+ .../bearer.c:166 bearer_name_validate() error: strcpy() 'media_name' too large for 'name_parts->media_name' (32 vs 16)
+ .../bearer.c:167 bearer_name_validate() error: strcpy() 'if_name' too large for 'name_parts->if_name' (1010102 vs 16)
+
+This does seem to be the case so guard against this possibility by using
+strscpy() and failing if truncation occurs.
+
+Introduced by commit b97bf3fd8f6a ("[TIPC] Initial merge")
+
+Compile tested only.
+
+Reviewed-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20240801-tipic-overrun-v2-1-c5b869d1f074@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/bearer.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
+index 5a526ebafeb4b..3c9e25f6a1d22 100644
+--- a/net/tipc/bearer.c
++++ b/net/tipc/bearer.c
+@@ -163,8 +163,12 @@ static int bearer_name_validate(const char *name,
+       /* return bearer name components, if necessary */
+       if (name_parts) {
+-              strcpy(name_parts->media_name, media_name);
+-              strcpy(name_parts->if_name, if_name);
++              if (strscpy(name_parts->media_name, media_name,
++                          TIPC_MAX_MEDIA_NAME) < 0)
++                      return 0;
++              if (strscpy(name_parts->if_name, if_name,
++                          TIPC_MAX_IF_NAME) < 0)
++                      return 0;
+       }
+       return 1;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/tools-hv-add-memory-allocation-check-in-hv_fcopy_sta.patch b/queue-6.10/tools-hv-add-memory-allocation-check-in-hv_fcopy_sta.patch
new file mode 100644 (file)
index 0000000..8a16500
--- /dev/null
@@ -0,0 +1,44 @@
+From 2bcbd25b52f61aaf240438243ca56e7f9fda35a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 02:13:33 -0700
+Subject: tools/hv: Add memory allocation check in hv_fcopy_start
+
+From: Zhu Jun <zhujun2@cmss.chinamobile.com>
+
+[ Upstream commit 94e86b174d103d941b4afc4f016af8af9e5352fa ]
+
+Added error handling for memory allocation failures
+of file_name and path_name.
+
+Signed-off-by: Zhu Jun <zhujun2@cmss.chinamobile.com>
+Reviewed-by: Dexuan Cui <decui@microsoft.com>
+Tested-by: Saurabh Sengar <ssengar@linux.microsoft.com>
+Link: https://lore.kernel.org/r/20240906091333.11419-1-zhujun2@cmss.chinamobile.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Message-ID: <20240906091333.11419-1-zhujun2@cmss.chinamobile.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/hv/hv_fcopy_uio_daemon.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/tools/hv/hv_fcopy_uio_daemon.c b/tools/hv/hv_fcopy_uio_daemon.c
+index 3ce316cc9f970..7a00f3066a980 100644
+--- a/tools/hv/hv_fcopy_uio_daemon.c
++++ b/tools/hv/hv_fcopy_uio_daemon.c
+@@ -296,6 +296,13 @@ static int hv_fcopy_start(struct hv_start_fcopy *smsg_in)
+       file_name = (char *)malloc(file_size * sizeof(char));
+       path_name = (char *)malloc(path_size * sizeof(char));
++      if (!file_name || !path_name) {
++              free(file_name);
++              free(path_name);
++              syslog(LOG_ERR, "Can't allocate memory for file name and/or path name");
++              return HV_E_FAIL;
++      }
++
+       wcstoutf8(file_name, (__u16 *)in_file_name, file_size);
+       wcstoutf8(path_name, (__u16 *)in_path_name, path_size);
+-- 
+2.43.0
+
diff --git a/queue-6.10/tools-nolibc-powerpc-limit-stack-protector-workaroun.patch b/queue-6.10/tools-nolibc-powerpc-limit-stack-protector-workaroun.patch
new file mode 100644 (file)
index 0000000..354fffd
--- /dev/null
@@ -0,0 +1,41 @@
+From f37f1865e22086d812ac5227efd2ba3a6b28133b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Aug 2024 23:51:39 +0200
+Subject: tools/nolibc: powerpc: limit stack-protector workaround to GCC
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit 1daea158d0aae0770371f3079305a29fdb66829e ]
+
+As mentioned in the comment, the workaround for
+__attribute__((no_stack_protector)) is only necessary on GCC.
+Avoid applying the workaround on clang, as clang does not recognize
+__attribute__((__optimize__)) and would fail.
+
+Acked-by: Willy Tarreau <w@1wt.eu>
+Link: https://lore.kernel.org/r/20240807-nolibc-llvm-v2-3-c20f2f5fc7c2@weissschuh.net
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/include/nolibc/arch-powerpc.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h
+index ac212e6185b26..41ebd394b90c7 100644
+--- a/tools/include/nolibc/arch-powerpc.h
++++ b/tools/include/nolibc/arch-powerpc.h
+@@ -172,7 +172,7 @@
+       _ret;                                                                \
+ })
+-#ifndef __powerpc64__
++#if !defined(__powerpc64__) && !defined(__clang__)
+ /* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0),
+  * "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but
+  * works with __attribute__((__optimize__("-fno-stack-protector")))
+-- 
+2.43.0
+
diff --git a/queue-6.10/tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch b/queue-6.10/tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch
new file mode 100644 (file)
index 0000000..d142b6a
--- /dev/null
@@ -0,0 +1,68 @@
+From 2ea063330328c53e62f471028a5c2dcf81290ec2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 15:47:44 +0200
+Subject: tools/x86/kcpuid: Protect against faulty "max subleaf" values
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ahmed S. Darwish <darwi@linutronix.de>
+
+[ Upstream commit cf96ab1a966b87b09fdd9e8cc8357d2d00776a3a ]
+
+Protect against the kcpuid code parsing faulty max subleaf numbers
+through a min() expression.  Thus, ensuring that max_subleaf will always
+be ≤ MAX_SUBLEAF_NUM.
+
+Use "u32" for the subleaf numbers since kcpuid is compiled with -Wextra,
+which includes signed/unsigned comparisons warnings.
+
+Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20240718134755.378115-5-darwi@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/arch/x86/kcpuid/kcpuid.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/tools/arch/x86/kcpuid/kcpuid.c b/tools/arch/x86/kcpuid/kcpuid.c
+index 24b7d017ec2c1..b7965dfff33a9 100644
+--- a/tools/arch/x86/kcpuid/kcpuid.c
++++ b/tools/arch/x86/kcpuid/kcpuid.c
+@@ -7,7 +7,8 @@
+ #include <string.h>
+ #include <getopt.h>
+-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++#define min(a, b)     (((a) < (b)) ? (a) : (b))
+ typedef unsigned int u32;
+ typedef unsigned long long u64;
+@@ -207,12 +208,9 @@ static void raw_dump_range(struct cpuid_range *range)
+ #define MAX_SUBLEAF_NUM               32
+ struct cpuid_range *setup_cpuid_range(u32 input_eax)
+ {
+-      u32 max_func, idx_func;
+-      int subleaf;
++      u32 max_func, idx_func, subleaf, max_subleaf;
++      u32 eax, ebx, ecx, edx, f = input_eax;
+       struct cpuid_range *range;
+-      u32 eax, ebx, ecx, edx;
+-      u32 f = input_eax;
+-      int max_subleaf;
+       bool allzero;
+       eax = input_eax;
+@@ -258,7 +256,7 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
+                * others have to be tried (0xf)
+                */
+               if (f == 0x7 || f == 0x14 || f == 0x17 || f == 0x18)
+-                      max_subleaf = (eax & 0xff) + 1;
++                      max_subleaf = min((eax & 0xff) + 1, max_subleaf);
+               if (f == 0xb)
+                       max_subleaf = 2;
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch b/queue-6.10/wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch
new file mode 100644 (file)
index 0000000..b248ddb
--- /dev/null
@@ -0,0 +1,43 @@
+From 3665bac96756fc8530b8e6e7a1501920a4c8567a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jul 2024 12:38:11 +0530
+Subject: wifi: ath11k: fix array out-of-bound access in SoC stats
+
+From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+
+[ Upstream commit 69f253e46af98af17e3efa3e5dfa72fcb7d1983d ]
+
+Currently, the ath11k_soc_dp_stats::hal_reo_error array is defined with a
+maximum size of DP_REO_DST_RING_MAX. However, the ath11k_dp_process_rx()
+function access ath11k_soc_dp_stats::hal_reo_error using the REO
+destination SRNG ring ID, which is incorrect. SRNG ring ID differ from
+normal ring ID, and this usage leads to out-of-bounds array access. To fix
+this issue, modify ath11k_dp_process_rx() to use the normal ring ID
+directly instead of the SRNG ring ID to avoid out-of-bounds array access.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240704070811.4186543-3-quic_periyasa@quicinc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index aabde24d87632..88c7a7289d06e 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -2697,7 +2697,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id,
+               if (unlikely(push_reason !=
+                            HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) {
+                       dev_kfree_skb_any(msdu);
+-                      ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++;
++                      ab->soc_stats.hal_reo_error[ring_id]++;
+                       continue;
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-ath12k-fix-array-out-of-bound-access-in-soc-sta.patch b/queue-6.10/wifi-ath12k-fix-array-out-of-bound-access-in-soc-sta.patch
new file mode 100644 (file)
index 0000000..6e92357
--- /dev/null
@@ -0,0 +1,43 @@
+From 3f3ee8b33967bc78c764a4200e7a903d0f9d02c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jul 2024 12:38:10 +0530
+Subject: wifi: ath12k: fix array out-of-bound access in SoC stats
+
+From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+
+[ Upstream commit e106b7ad13c1d246adaa57df73edb8f8b8acb240 ]
+
+Currently, the ath12k_soc_dp_stats::hal_reo_error array is defined with a
+maximum size of DP_REO_DST_RING_MAX. However, the ath12k_dp_rx_process()
+function access ath12k_soc_dp_stats::hal_reo_error using the REO
+destination SRNG ring ID, which is incorrect. SRNG ring ID differ from
+normal ring ID, and this usage leads to out-of-bounds array access. To
+fix this issue, modify ath12k_dp_rx_process() to use the normal ring ID
+directly instead of the SRNG ring ID to avoid out-of-bounds array access.
+
+Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240704070811.4186543-2-quic_periyasa@quicinc.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath12k/dp_rx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
+index 3cdc4c51d6dfe..f8767496fa543 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
+@@ -2702,7 +2702,7 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id,
+               if (push_reason !=
+                   HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
+                       dev_kfree_skb_any(msdu);
+-                      ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++;
++                      ab->soc_stats.hal_reo_error[ring_id]++;
+                       continue;
+               }
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch b/queue-6.10/wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch
new file mode 100644 (file)
index 0000000..15d21b2
--- /dev/null
@@ -0,0 +1,47 @@
+From f44fb444ccfb8db1ee0cbed0eac8c37665a16374 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 25 Jul 2024 14:17:43 +0300
+Subject: wifi: ath9k: fix possible integer overflow in ath9k_get_et_stats()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Dmitry Kandybka <d.kandybka@gmail.com>
+
+[ Upstream commit 3f66f26703093886db81f0610b97a6794511917c ]
+
+In 'ath9k_get_et_stats()', promote TX stats counters to 'u64'
+to avoid possible integer overflow. Compile tested only.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Signed-off-by: Dmitry Kandybka <d.kandybka@gmail.com>
+Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240725111743.14422-1-d.kandybka@gmail.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/debug.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
+index bf3da631c69fd..51abc470125b3 100644
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1325,11 +1325,11 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
+       struct ath_softc *sc = hw->priv;
+       int i = 0;
+-      data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all +
++      data[i++] = ((u64)sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all);
+-      data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all +
++      data[i++] = ((u64)sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all);
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch b/queue-6.10/wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch
new file mode 100644 (file)
index 0000000..f37b841
--- /dev/null
@@ -0,0 +1,59 @@
+From c63db31fcb616e4286db225e28fd16cef7345c91 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Aug 2024 16:24:46 +0200
+Subject: wifi: ath9k_htc: Use __skb_set_length() for resetting urb before
+ resubmit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Toke Høiland-Jørgensen <toke@redhat.com>
+
+[ Upstream commit 94745807f3ebd379f23865e6dab196f220664179 ]
+
+Syzbot points out that skb_trim() has a sanity check on the existing length of
+the skb, which can be uninitialised in some error paths. The intent here is
+clearly just to reset the length to zero before resubmitting, so switch to
+calling __skb_set_length(skb, 0) directly. In addition, __skb_set_length()
+already contains a call to skb_reset_tail_pointer(), so remove the redundant
+call.
+
+The syzbot report came from ath9k_hif_usb_reg_in_cb(), but there's a similar
+usage of skb_trim() in ath9k_hif_usb_rx_cb(), change both while we're at it.
+
+Reported-by: syzbot+98afa303be379af6cdb2@syzkaller.appspotmail.com
+Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://patch.msgid.link/20240812142447.12328-1-toke@toke.dk
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/hif_usb.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
+index 0c7841f952287..a3733c9b484e4 100644
+--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
+@@ -716,8 +716,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
+       }
+ resubmit:
+-      skb_reset_tail_pointer(skb);
+-      skb_trim(skb, 0);
++      __skb_set_length(skb, 0);
+       usb_anchor_urb(urb, &hif_dev->rx_submitted);
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+@@ -754,8 +753,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
+       case -ESHUTDOWN:
+               goto free_skb;
+       default:
+-              skb_reset_tail_pointer(skb);
+-              skb_trim(skb, 0);
++              __skb_set_length(skb, 0);
+               goto resubmit;
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-cfg80211-set-correct-chandef-when-starting-cac.patch b/queue-6.10/wifi-cfg80211-set-correct-chandef-when-starting-cac.patch
new file mode 100644 (file)
index 0000000..ff43cfa
--- /dev/null
@@ -0,0 +1,77 @@
+From 12b90ae642652779cbfe61cc4b6f69f86f8e300c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Aug 2024 16:24:18 +0200
+Subject: wifi: cfg80211: Set correct chandef when starting CAC
+
+From: Issam Hamdi <ih@simonwunderlich.de>
+
+[ Upstream commit 20361712880396e44ce80aaeec2d93d182035651 ]
+
+When starting CAC in a mode other than AP mode, it return a
+"WARNING: CPU: 0 PID: 63 at cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]"
+caused by the chandef.chan being null at the end of CAC.
+
+Solution: Ensure the channel definition is set for the different modes
+when starting CAC to avoid getting a NULL 'chan' at the end of CAC.
+
+ Call Trace:
+  ? show_regs.part.0+0x14/0x16
+  ? __warn+0x67/0xc0
+  ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
+  ? report_bug+0xa7/0x130
+  ? exc_overflow+0x30/0x30
+  ? handle_bug+0x27/0x50
+  ? exc_invalid_op+0x18/0x60
+  ? handle_exception+0xf6/0xf6
+  ? exc_overflow+0x30/0x30
+  ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
+  ? exc_overflow+0x30/0x30
+  ? cfg80211_chandef_dfs_usable+0x20/0xaf [cfg80211]
+  ? regulatory_propagate_dfs_state.cold+0x1b/0x4c [cfg80211]
+  ? cfg80211_propagate_cac_done_wk+0x1a/0x30 [cfg80211]
+  ? process_one_work+0x165/0x280
+  ? worker_thread+0x120/0x3f0
+  ? kthread+0xc2/0xf0
+  ? process_one_work+0x280/0x280
+  ? kthread_complete_and_exit+0x20/0x20
+  ? ret_from_fork+0x19/0x24
+
+Reported-by: Kretschmer Mathias <mathias.kretschmer@fit.fraunhofer.de>
+Signed-off-by: Issam Hamdi <ih@simonwunderlich.de>
+Link: https://patch.msgid.link/20240816142418.3381951-1-ih@simonwunderlich.de
+[shorten subject, remove OCB, reorder cases to match previous list]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/wireless/nl80211.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index e3bf14e489c5d..9675ceaa5bf60 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -10024,7 +10024,20 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+       err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
+       if (!err) {
+-              wdev->links[0].ap.chandef = chandef;
++              switch (wdev->iftype) {
++              case NL80211_IFTYPE_AP:
++              case NL80211_IFTYPE_P2P_GO:
++                      wdev->links[0].ap.chandef = chandef;
++                      break;
++              case NL80211_IFTYPE_ADHOC:
++                      wdev->u.ibss.chandef = chandef;
++                      break;
++              case NL80211_IFTYPE_MESH_POINT:
++                      wdev->u.mesh.chandef = chandef;
++                      break;
++              default:
++                      break;
++              }
+               wdev->cac_started = true;
+               wdev->cac_start_time = jiffies;
+               wdev->cac_time_ms = cac_time_ms;
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-iwlwifi-allow-only-cn-mcc-from-wrdd.patch b/queue-6.10/wifi-iwlwifi-allow-only-cn-mcc-from-wrdd.patch
new file mode 100644 (file)
index 0000000..3f6c88a
--- /dev/null
@@ -0,0 +1,81 @@
+From acc1127d65e9c0ff1fe4c2e397c7eed9873769b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 23:22:49 +0300
+Subject: wifi: iwlwifi: allow only CN mcc from WRDD
+
+From: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+
+[ Upstream commit ff5aabe7c2a4a4b089a9ced0cb3d0e284963a7dd ]
+
+Block other mcc expect CN from WRDD ACPI.
+
+Signed-off-by: Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240808232017.fe6ea7aa4b39.I86004687a2963fe26f990770aca103e2f5cb1628@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/fw/acpi.c       | 5 +++++
+ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 2 ++
+ drivers/net/wireless/intel/iwlwifi/fw/uefi.c       | 2 +-
+ drivers/net/wireless/intel/iwlwifi/fw/uefi.h       | 2 --
+ 4 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+index ba9e656037a20..9b3d3405fb83d 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+@@ -356,6 +356,11 @@ int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
+       }
+       mcc_val = wifi_pkg->package.elements[1].integer.value;
++      if (mcc_val != BIOS_MCC_CHINA) {
++              ret = -EINVAL;
++              IWL_DEBUG_RADIO(fwrt, "ACPI WRDD is supported only for CN\n");
++              goto out_free;
++      }
+       mcc[0] = (mcc_val >> 8) & 0xff;
+       mcc[1] = mcc_val & 0xff;
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+index 633c9ad9af841..ecf482647617c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+@@ -45,6 +45,8 @@
+ #define IWL_WTAS_ENABLE_IEC_MSK       0x4
+ #define IWL_WTAS_USA_UHB_MSK          BIT(16)
++#define BIOS_MCC_CHINA 0x434e
++
+ /*
+  * The profile for revision 2 is a superset of revision 1, which is in
+  * turn a superset of revision 0.  So we can store all revisions
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+index fb982d4fe8510..2cf878f237ac6 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+@@ -638,7 +638,7 @@ int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
+               goto out;
+       }
+-      if (data->mcc != UEFI_MCC_CHINA) {
++      if (data->mcc != BIOS_MCC_CHINA) {
+               ret = -EINVAL;
+               IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n");
+               goto out;
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+index 1f8884ca8997c..e0ef981cd8f28 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+@@ -149,8 +149,6 @@ struct uefi_cnv_var_splc {
+       u32 default_pwr_limit;
+ } __packed;
+-#define UEFI_MCC_CHINA 0x434e
+-
+ /* struct uefi_cnv_var_wrdd - WRDD table as defined in UEFI
+  * @revision: the revision of the table
+  * @mcc: country identifier as defined in ISO/IEC 3166-1 Alpha 2 code
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-iwlwifi-mvm-avoid-null-pointer-dereference.patch b/queue-6.10/wifi-iwlwifi-mvm-avoid-null-pointer-dereference.patch
new file mode 100644 (file)
index 0000000..5f90b6d
--- /dev/null
@@ -0,0 +1,76 @@
+From a52126c39e9cb42d5da72fad02f626bc0f9f2470 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 19:17:09 +0300
+Subject: wifi: iwlwifi: mvm: avoid NULL pointer dereference
+
+From: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+
+[ Upstream commit 557a6cd847645e667f3b362560bd7e7c09aac284 ]
+
+iwl_mvm_tx_skb_sta() and iwl_mvm_tx_mpdu() verify that the mvmvsta
+pointer is not NULL.
+It retrieves this pointer using iwl_mvm_sta_from_mac80211, which is
+dereferencing the ieee80211_sta pointer.
+If sta is NULL, iwl_mvm_sta_from_mac80211 will dereference a NULL
+pointer.
+Fix this by checking the sta pointer before retrieving the mvmsta
+from it. If sta is not NULL, then mvmsta isn't either.
+
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Reviewed-by: Johannes Berg <johannes.berg@intel.com>
+Link: https://patch.msgid.link/20240825191257.880921ce23b7.I340052d70ab6d3410724ce955eb00da10e08188f@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+index 1d695ece93e9e..51c12d70e8c23 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+@@ -1195,6 +1195,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+       bool is_ampdu = false;
+       int hdrlen;
++      if (WARN_ON_ONCE(!sta))
++              return -1;
++
+       mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       fc = hdr->frame_control;
+       hdrlen = ieee80211_hdrlen(fc);
+@@ -1202,9 +1205,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+       if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
+               return -1;
+-      if (WARN_ON_ONCE(!mvmsta))
+-              return -1;
+-
+       if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+               return -1;
+@@ -1335,7 +1335,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
+                      struct ieee80211_sta *sta)
+ {
+-      struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
++      struct iwl_mvm_sta *mvmsta;
+       struct ieee80211_tx_info info;
+       struct sk_buff_head mpdus_skbs;
+       struct ieee80211_vif *vif;
+@@ -1344,9 +1344,11 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
+       struct sk_buff *orig_skb = skb;
+       const u8 *addr3;
+-      if (WARN_ON_ONCE(!mvmsta))
++      if (WARN_ON_ONCE(!sta))
+               return -1;
++      mvmsta = iwl_mvm_sta_from_mac80211(sta);
++
+       if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+               return -1;
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-iwlwifi-mvm-drop-wrong-sta-selection-in-tx.patch b/queue-6.10/wifi-iwlwifi-mvm-drop-wrong-sta-selection-in-tx.patch
new file mode 100644 (file)
index 0000000..0f219d5
--- /dev/null
@@ -0,0 +1,64 @@
+From bde3ed62dce95a8ad41ec0a20088e2569d184351 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Aug 2024 23:22:48 +0300
+Subject: wifi: iwlwifi: mvm: drop wrong STA selection in TX
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 1c7e1068a7c9c39ed27636db93e71911e0045419 ]
+
+This shouldn't happen at all, since in station mode all MMPDUs
+go through the TXQ for the STA, and not this function. There
+may or may not be a race in mac80211 through which this might
+happen for some frames while a station is being added, but in
+that case we can also just drop the frame and pretend the STA
+didn't exist yet.
+
+Also, the code is simply wrong since it uses deflink, and it's
+not easy to fix it since the mvmvif->ap_sta pointer cannot be
+used without the mutex, and perhaps the right link might not
+even be known.
+
+Just drop the frame at that point instead of trying to fix it
+up.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240808232017.45ad105dc7fe.I6d45c82e5758395d9afb8854057ded03c7dc81d7@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/mvm/mac80211.c    | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+index 83551d962a46c..6673a4e467c0b 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+@@ -834,20 +834,10 @@ void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
+       if (ieee80211_is_mgmt(hdr->frame_control))
+               sta = NULL;
+-      /* If there is no sta, and it's not offchannel - send through AP */
++      /* this shouldn't even happen: just drop */
+       if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION &&
+-          !offchannel) {
+-              struct iwl_mvm_vif *mvmvif =
+-                      iwl_mvm_vif_from_mac80211(info->control.vif);
+-              u8 ap_sta_id = READ_ONCE(mvmvif->deflink.ap_sta_id);
+-
+-              if (ap_sta_id < mvm->fw->ucode_capa.num_stations) {
+-                      /* mac80211 holds rcu read lock */
+-                      sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]);
+-                      if (IS_ERR_OR_NULL(sta))
+-                              goto drop;
+-              }
+-      }
++          !offchannel)
++              goto drop;
+       if (tmp_sta && !sta && link_id != IEEE80211_LINK_UNSPECIFIED &&
+           !ieee80211_is_probe_resp(hdr->frame_control)) {
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch b/queue-6.10/wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch
new file mode 100644 (file)
index 0000000..9ba8978
--- /dev/null
@@ -0,0 +1,153 @@
+From 63f36f15e9fa2304adc241a76f7b9165db1b83b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 08:56:37 +0300
+Subject: wifi: iwlwifi: mvm: Fix a race in scan abort flow
+
+From: Ilan Peer <ilan.peer@intel.com>
+
+[ Upstream commit 87c1c28a9aa149489e1667f5754fc24f4973d2d0 ]
+
+When the upper layer requests to cancel an ongoing scan, a race
+is possible in which by the time the driver starts to handle the
+upper layers scan cancel flow, the FW already completed handling
+the scan request and the driver received the scan complete
+notification but still did not handle the notification. In such a
+case the FW will simply ignore the scan abort request coming from
+the driver, no notification would arrive from the FW and the entire
+abort flow would be considered a failure.
+
+To better handle this, check the status code returned by the FW for
+the scan abort command. In case the status indicates that
+no scan was aborted, complete the scan abort flow with success, i.e.,
+the scan was aborted, as the flow is expected to consume the scan
+complete notification.
+
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240825085558.483989d3baef.I3340556a222388504c6330b333360bf77d10f9e2@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/wireless/intel/iwlwifi/fw/api/scan.h  | 13 ++++++
+ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 42 +++++++++++++++----
+ 2 files changed, 47 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+index 6684506f4fc48..6cf237850ea0c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
++++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+@@ -1132,6 +1132,19 @@ struct iwl_umac_scan_abort {
+       __le32 flags;
+ } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */
++/**
++ * enum iwl_umac_scan_abort_status
++ *
++ * @IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS: scan was successfully aborted
++ * @IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS: scan abort is in progress
++ * @IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND: nothing to abort
++ */
++enum iwl_umac_scan_abort_status {
++      IWL_UMAC_SCAN_ABORT_STATUS_SUCCESS = 0,
++      IWL_UMAC_SCAN_ABORT_STATUS_IN_PROGRESS,
++      IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
++};
++
+ /**
+  * struct iwl_umac_scan_complete
+  * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+index d7c276237c74e..d8a3d47f5c072 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+@@ -3313,13 +3313,23 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
+                      mvm->scan_start);
+ }
+-static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
++static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type, bool *wait)
+ {
+-      struct iwl_umac_scan_abort cmd = {};
++      struct iwl_umac_scan_abort abort_cmd = {};
++      struct iwl_host_cmd cmd = {
++              .id = WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC),
++              .len = { sizeof(abort_cmd), },
++              .data = { &abort_cmd, },
++              .flags = CMD_SEND_IN_RFKILL,
++      };
++
+       int uid, ret;
++      u32 status = IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND;
+       lockdep_assert_held(&mvm->mutex);
++      *wait = true;
++
+       /* We should always get a valid index here, because we already
+        * checked that this type of scan was running in the generic
+        * code.
+@@ -3328,17 +3338,28 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
+       if (WARN_ON_ONCE(uid < 0))
+               return uid;
+-      cmd.uid = cpu_to_le32(uid);
++      abort_cmd.uid = cpu_to_le32(uid);
+       IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid);
+-      ret = iwl_mvm_send_cmd_pdu(mvm,
+-                                 WIDE_ID(IWL_ALWAYS_LONG_GROUP, SCAN_ABORT_UMAC),
+-                                 CMD_SEND_IN_RFKILL, sizeof(cmd), &cmd);
++      ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
++
++      IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d, status=%u\n", ret, status);
+       if (!ret)
+               mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
+-      IWL_DEBUG_SCAN(mvm, "Scan abort: ret=%d\n", ret);
++      /* Handle the case that the FW is no longer familiar with the scan that
++       * is to be stopped. In such a case, it is expected that the scan
++       * complete notification was already received but not yet processed.
++       * In such a case, there is no need to wait for a scan complete
++       * notification and the flow should continue similar to the case that
++       * the scan was really aborted.
++       */
++      if (status == IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND) {
++              mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT;
++              *wait = false;
++      }
++
+       return ret;
+ }
+@@ -3348,6 +3369,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
+       static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC,
+                                             SCAN_OFFLOAD_COMPLETE, };
+       int ret;
++      bool wait = true;
+       lockdep_assert_held(&mvm->mutex);
+@@ -3359,7 +3381,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
+       IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
+       if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+-              ret = iwl_mvm_umac_scan_abort(mvm, type);
++              ret = iwl_mvm_umac_scan_abort(mvm, type, &wait);
+       else
+               ret = iwl_mvm_lmac_scan_abort(mvm);
+@@ -3367,6 +3389,10 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
+               IWL_DEBUG_SCAN(mvm, "couldn't stop scan type %d\n", type);
+               iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
+               return ret;
++      } else if (!wait) {
++              IWL_DEBUG_SCAN(mvm, "no need to wait for scan type %d\n", type);
++              iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
++              return 0;
+       }
+       return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done,
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-iwlwifi-mvm-use-correct-key-iteration.patch b/queue-6.10/wifi-iwlwifi-mvm-use-correct-key-iteration.patch
new file mode 100644 (file)
index 0000000..8c4df7c
--- /dev/null
@@ -0,0 +1,61 @@
+From 00dde574a872171c2b39aec712379fbb9573f54f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 20:20:05 +0300
+Subject: wifi: iwlwifi: mvm: use correct key iteration
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 4f1591d292277eec51d027405a92f0d4ef5e299e ]
+
+In the cases changed here, key iteration isn't done from
+an RCU critical section, but rather using the wiphy lock
+as protection. Therefore, just use ieee80211_iter_keys().
+The link switch case can therefore also use sync commands.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240729201718.69a2d18580c1.I2148e04d4b467d0b100beac8f7e449bfaaf775a5@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+index 8a38fc4b0b0f9..455f5f4175064 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+@@ -144,7 +144,7 @@ static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
+       if (sta != data->sta || key->link_id >= 0)
+               return;
+-      err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cmd), &cmd);
++      err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
+       if (err)
+               data->err = err;
+@@ -162,8 +162,8 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
+               .new_sta_mask = new_sta_mask,
+       };
+-      ieee80211_iter_keys_rcu(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
+-                              &data);
++      ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
++                          &data);
+       return data.err;
+ }
+@@ -402,7 +402,7 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
+       if (!sec_key_ver)
+               return;
+-      ieee80211_iter_keys_rcu(mvm->hw, vif,
+-                              iwl_mvm_sec_key_remove_ap_iter,
+-                              (void *)(uintptr_t)link_id);
++      ieee80211_iter_keys(mvm->hw, vif,
++                          iwl_mvm_sec_key_remove_ap_iter,
++                          (void *)(uintptr_t)link_id);
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-mac80211-fix-rcu-list-iterations.patch b/queue-6.10/wifi-mac80211-fix-rcu-list-iterations.patch
new file mode 100644 (file)
index 0000000..a70e65c
--- /dev/null
@@ -0,0 +1,84 @@
+From f55b2fdf66edf1fd4b128db20b01511e66e84562 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 09:49:40 +0200
+Subject: wifi: mac80211: fix RCU list iterations
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit ac35180032fbc5d80b29af00ba4881815ceefcb6 ]
+
+There are a number of places where RCU list iteration is
+used, but that aren't (always) called with RCU held. Use
+just list_for_each_entry() in most, and annotate iface
+iteration with the required locks.
+
+Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
+Link: https://patch.msgid.link/20240827094939.ed8ac0b2f897.I8443c9c3c0f8051841353491dae758021b53115e@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mac80211/chan.c | 4 +++-
+ net/mac80211/mlme.c | 2 +-
+ net/mac80211/scan.c | 2 +-
+ net/mac80211/util.c | 4 +++-
+ 4 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index e6a7ff6ca6797..db5675d24e488 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -281,7 +281,9 @@ ieee80211_get_max_required_bw(struct ieee80211_link_data *link)
+       enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+       struct sta_info *sta;
+-      list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
++      lockdep_assert_wiphy(sdata->local->hw.wiphy);
++
++      list_for_each_entry(sta, &sdata->local->sta_list, list) {
+               if (sdata != sta->sdata &&
+                   !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
+                       continue;
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 1faf4d7c115f0..71cc5eb35bfcb 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -1020,7 +1020,7 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
+               bool disable_mu_mimo = false;
+               struct ieee80211_sub_if_data *other;
+-              list_for_each_entry_rcu(other, &local->interfaces, list) {
++              list_for_each_entry(other, &local->interfaces, list) {
+                       if (other->vif.bss_conf.mu_mimo_owner) {
+                               disable_mu_mimo = true;
+                               break;
+diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
+index 1c5d99975ad04..3b2bde6360bcb 100644
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -504,7 +504,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+        * the scan was in progress; if there was none this will
+        * just be a no-op for the particular interface.
+        */
+-      list_for_each_entry_rcu(sdata, &local->interfaces, list) {
++      list_for_each_entry(sdata, &local->interfaces, list) {
+               if (ieee80211_sdata_running(sdata))
+                       wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
+       }
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index c11dbe82ae1b3..d10e0c528c1bf 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -751,7 +751,9 @@ static void __iterate_interfaces(struct ieee80211_local *local,
+       struct ieee80211_sub_if_data *sdata;
+       bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
+-      list_for_each_entry_rcu(sdata, &local->interfaces, list) {
++      list_for_each_entry_rcu(sdata, &local->interfaces, list,
++                              lockdep_is_held(&local->iflist_mtx) ||
++                              lockdep_is_held(&local->hw.wiphy->mtx)) {
+               switch (sdata->vif.type) {
+               case NL80211_IFTYPE_MONITOR:
+                       if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-mt76-mt7915-add-dummy-hw-offload-of-ieee-802.11.patch b/queue-6.10/wifi-mt76-mt7915-add-dummy-hw-offload-of-ieee-802.11.patch
new file mode 100644 (file)
index 0000000..49ba82e
--- /dev/null
@@ -0,0 +1,62 @@
+From 0e08acaf63290196183136ca301a62d8f383794e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 11:30:03 +0200
+Subject: wifi: mt76: mt7915: add dummy HW offload of IEEE 802.11 fragmentation
+
+From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+
+[ Upstream commit f2cc859149240d910fdc6405717673e0b84bfda8 ]
+
+Currently, CONNAC2 series do not support encryption for fragmented Tx frames.
+Therefore, add dummy function mt7915_set_frag_threshold() to prevent SW
+IEEE 802.11 fragmentation.
+
+Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Link: https://patch.msgid.link/20240827093011.18621-16-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 +
+ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+index 7bc3b4cd35925..6bef96e3d2a3d 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+@@ -400,6 +400,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
+       ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
+       ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
+       ieee80211_hw_set(hw, WANT_MONITOR_VIF);
++      ieee80211_hw_set(hw, SUPPORTS_TX_FRAG);
+       hw->max_tx_fragments = 4;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+index eea41b29f0967..3b2dcb410e0f0 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+@@ -1577,6 +1577,12 @@ mt7915_twt_teardown_request(struct ieee80211_hw *hw,
+       mutex_unlock(&dev->mt76.mutex);
+ }
++static int
++mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val)
++{
++      return 0;
++}
++
+ static int
+ mt7915_set_radar_background(struct ieee80211_hw *hw,
+                           struct cfg80211_chan_def *chandef)
+@@ -1707,6 +1713,7 @@ const struct ieee80211_ops mt7915_ops = {
+       .sta_set_decap_offload = mt7915_sta_set_decap_offload,
+       .add_twt_setup = mt7915_mac_add_twt_setup,
+       .twt_teardown_request = mt7915_twt_teardown_request,
++      .set_frag_threshold = mt7915_set_frag_threshold,
+       CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
+       CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
+ #ifdef CONFIG_MAC80211_DEBUGFS
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch b/queue-6.10/wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch
new file mode 100644 (file)
index 0000000..c15442a
--- /dev/null
@@ -0,0 +1,47 @@
+From 14d88646cadae3d8d26340cd2e063dd088c15da5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 11:29:54 +0200
+Subject: wifi: mt76: mt7915: disable tx worker during tx BA session
+ enable/disable
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 256cbd26fbafb30ba3314339106e5c594e9bd5f9 ]
+
+Avoids firmware race condition.
+
+Link: https://patch.msgid.link/20240827093011.18621-7-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+index 9599adf104b16..758249b20c222 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+@@ -690,13 +690,17 @@ int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
+ {
+       struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
+       struct mt7915_vif *mvif = msta->vif;
++      int ret;
++      mt76_worker_disable(&dev->mt76.tx_worker);
+       if (enable && !params->amsdu)
+               msta->wcid.amsdu = false;
++      ret = mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
++                                   MCU_EXT_CMD(STA_REC_UPDATE),
++                                   enable, true);
++      mt76_worker_enable(&dev->mt76.tx_worker);
+-      return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
+-                                    MCU_EXT_CMD(STA_REC_UPDATE),
+-                                    enable, true);
++      return ret;
+ }
+ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch b/queue-6.10/wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch
new file mode 100644 (file)
index 0000000..1cde823
--- /dev/null
@@ -0,0 +1,41 @@
+From d9e99ceffe723df4602667857ab801d64e258eb8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Aug 2024 11:30:04 +0200
+Subject: wifi: mt76: mt7915: hold dev->mt76.mutex while disabling tx worker
+
+From: Felix Fietkau <nbd@nbd.name>
+
+[ Upstream commit 8f7152f10cb434f954aeff85ca1be9cd4d01912b ]
+
+Prevent racing against other functions disabling the same worker
+
+Link: https://patch.msgid.link/20240827093011.18621-17-nbd@nbd.name
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+index 8008ce3fa6c7e..387d47e9fcd38 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+@@ -1537,12 +1537,14 @@ void mt7915_mac_reset_work(struct work_struct *work)
+               set_bit(MT76_RESET, &phy2->mt76->state);
+               cancel_delayed_work_sync(&phy2->mt76->mac_work);
+       }
++
++      mutex_lock(&dev->mt76.mutex);
++
+       mt76_worker_disable(&dev->mt76.tx_worker);
+       mt76_for_each_q_rx(&dev->mt76, i)
+               napi_disable(&dev->mt76.napi[i]);
+       napi_disable(&dev->mt76.tx_napi);
+-      mutex_lock(&dev->mt76.mutex);
+       if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+               mtk_wed_device_stop(&dev->mt76.mmio.wed);
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch b/queue-6.10/wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch
new file mode 100644 (file)
index 0000000..a17689f
--- /dev/null
@@ -0,0 +1,62 @@
+From 6c70350cbdd8f21a143cf0f0cf7910f3711e1329 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Aug 2024 15:23:51 -0600
+Subject: wifi: mwifiex: Fix memcpy() field-spanning write warning in
+ mwifiex_cmd_802_11_scan_ext()
+
+From: Gustavo A. R. Silva <gustavoars@kernel.org>
+
+[ Upstream commit 498365e52bebcbc36a93279fe7e9d6aec8479cee ]
+
+Replace one-element array with a flexible-array member in
+`struct host_cmd_ds_802_11_scan_ext`.
+
+With this, fix the following warning:
+
+elo 16 17:51:58 surfacebook kernel: ------------[ cut here ]------------
+elo 16 17:51:58 surfacebook kernel: memcpy: detected field-spanning write (size 243) of single field "ext_scan->tlv_buffer" at drivers/net/wireless/marvell/mwifiex/scan.c:2239 (size 1)
+elo 16 17:51:58 surfacebook kernel: WARNING: CPU: 0 PID: 498 at drivers/net/wireless/marvell/mwifiex/scan.c:2239 mwifiex_cmd_802_11_scan_ext+0x83/0x90 [mwifiex]
+
+Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Closes: https://lore.kernel.org/linux-hardening/ZsZNgfnEwOcPdCly@black.fi.intel.com/
+Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Acked-by: Brian Norris <briannorris@chromium.org>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://patch.msgid.link/ZsZa5xRcsLq9D+RX@elsanto
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/marvell/mwifiex/fw.h   | 2 +-
+ drivers/net/wireless/marvell/mwifiex/scan.c | 3 +--
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
+index 3adc447b715f6..5b072120e3f21 100644
+--- a/drivers/net/wireless/marvell/mwifiex/fw.h
++++ b/drivers/net/wireless/marvell/mwifiex/fw.h
+@@ -1587,7 +1587,7 @@ struct host_cmd_ds_802_11_scan_rsp {
+ struct host_cmd_ds_802_11_scan_ext {
+       u32   reserved;
+-      u8    tlv_buffer[1];
++      u8    tlv_buffer[];
+ } __packed;
+ struct mwifiex_ie_types_bss_mode {
+diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
+index 0326b121747cb..17ce84f5207e3 100644
+--- a/drivers/net/wireless/marvell/mwifiex/scan.c
++++ b/drivers/net/wireless/marvell/mwifiex/scan.c
+@@ -2530,8 +2530,7 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+       ext_scan_resp = &resp->params.ext_scan;
+       tlv = (void *)ext_scan_resp->tlv_buffer;
+-      buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
+-                                            - 1);
++      buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN);
+       while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+               type = le16_to_cpu(tlv->type);
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-rtw88-select-want_dev_coredump.patch b/queue-6.10/wifi-rtw88-select-want_dev_coredump.patch
new file mode 100644 (file)
index 0000000..1a52309
--- /dev/null
@@ -0,0 +1,35 @@
+From 37fb0453726edd6f10f31d80cacd649c66d7fe6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jul 2024 15:06:15 +0800
+Subject: wifi: rtw88: select WANT_DEV_COREDUMP
+
+From: Zong-Zhe Yang <kevin_yang@realtek.com>
+
+[ Upstream commit 7e989b0c1e33210c07340bf5228aa83ea52515b5 ]
+
+We have invoked device coredump when fw crash.
+Should select WANT_DEV_COREDUMP by ourselves.
+
+Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240718070616.42217-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw88/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
+index 22838ede03cd8..02b0d698413be 100644
+--- a/drivers/net/wireless/realtek/rtw88/Kconfig
++++ b/drivers/net/wireless/realtek/rtw88/Kconfig
+@@ -12,6 +12,7 @@ if RTW88
+ config RTW88_CORE
+       tristate
++      select WANT_DEV_COREDUMP
+ config RTW88_PCI
+       tristate
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-rtw89-avoid-reading-out-of-bounds-when-loading-.patch b/queue-6.10/wifi-rtw89-avoid-reading-out-of-bounds-when-loading-.patch
new file mode 100644 (file)
index 0000000..e10fa72
--- /dev/null
@@ -0,0 +1,60 @@
+From 2208d13d0fb0ebbb11858943afceada65d4a03c7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Sep 2024 09:58:03 +0800
+Subject: wifi: rtw89: avoid reading out of bounds when loading TX power FW
+ elements
+
+From: Zong-Zhe Yang <kevin_yang@realtek.com>
+
+[ Upstream commit ed2e4bb17a4884cf29c3347353d8aabb7265b46c ]
+
+Because the loop-expression will do one more time before getting false from
+cond-expression, the original code copied one more entry size beyond valid
+region.
+
+Fix it by moving the entry copy to loop-body.
+
+Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240902015803.20420-1-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/core.h | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
+index 112bdd95fc6ea..504660ee3cba3 100644
+--- a/drivers/net/wireless/realtek/rtw89/core.h
++++ b/drivers/net/wireless/realtek/rtw89/core.h
+@@ -3888,16 +3888,22 @@ struct rtw89_txpwr_conf {
+       const void *data;
+ };
++static inline bool rtw89_txpwr_entcpy(void *entry, const void *cursor, u8 size,
++                                    const struct rtw89_txpwr_conf *conf)
++{
++      u8 valid_size = min(size, conf->ent_sz);
++
++      memcpy(entry, cursor, valid_size);
++      return true;
++}
++
+ #define rtw89_txpwr_conf_valid(conf) (!!(conf)->data)
+ #define rtw89_for_each_in_txpwr_conf(entry, cursor, conf) \
+-      for (typecheck(const void *, cursor), (cursor) = (conf)->data, \
+-           memcpy(&(entry), cursor, \
+-                  min_t(u8, sizeof(entry), (conf)->ent_sz)); \
++      for (typecheck(const void *, cursor), (cursor) = (conf)->data; \
+            (cursor) < (conf)->data + (conf)->num_ents * (conf)->ent_sz; \
+-           (cursor) += (conf)->ent_sz, \
+-           memcpy(&(entry), cursor, \
+-                  min_t(u8, sizeof(entry), (conf)->ent_sz)))
++           (cursor) += (conf)->ent_sz) \
++              if (rtw89_txpwr_entcpy(&(entry), cursor, sizeof(entry), conf))
+ struct rtw89_txpwr_byrate_data {
+       struct rtw89_txpwr_conf conf;
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch b/queue-6.10/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch
new file mode 100644 (file)
index 0000000..c229f3f
--- /dev/null
@@ -0,0 +1,124 @@
+From eed3c62494f930d48250a891c000992fe9e72b95 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Jul 2024 15:05:04 +0800
+Subject: wifi: rtw89: avoid to add interface to list twice when SER
+
+From: Chih-Kang Chang <gary.chang@realtek.com>
+
+[ Upstream commit 7dd5d2514a8ea58f12096e888b0bd050d7eae20a ]
+
+If SER L2 occurs during the WoWLAN resume flow, the add interface flow
+is triggered by ieee80211_reconfig(). However, due to
+rtw89_wow_resume() return failure, it will cause the add interface flow
+to be executed again, resulting in a double add list and causing a kernel
+panic. Therefore, we have added a check to prevent double adding of the
+list.
+
+list_add double add: new=ffff99d6992e2010, prev=ffff99d6992e2010, next=ffff99d695302628.
+------------[ cut here ]------------
+kernel BUG at lib/list_debug.c:37!
+invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
+CPU: 0 PID: 9 Comm: kworker/0:1 Tainted: G        W  O       6.6.30-02659-gc18865c4dfbd #1 770df2933251a0e3c888ba69d1053a817a6376a7
+Hardware name: HP Grunt/Grunt, BIOS Google_Grunt.11031.169.0 06/24/2021
+Workqueue: events_freezable ieee80211_restart_work [mac80211]
+RIP: 0010:__list_add_valid_or_report+0x5e/0xb0
+Code: c7 74 18 48 39 ce 74 13 b0 01 59 5a 5e 5f 41 58 41 59 41 5a 5d e9 e2 d6 03 00 cc 48 c7 c7 8d 4f 17 83 48 89 c2 e8 02 c0 00 00 <0f> 0b 48 c7 c7 aa 8c 1c 83 e8 f4 bf 00 00 0f 0b 48 c7 c7 c8 bc 12
+RSP: 0018:ffffa91b8007bc50 EFLAGS: 00010246
+RAX: 0000000000000058 RBX: ffff99d6992e0900 RCX: a014d76c70ef3900
+RDX: ffffa91b8007bae8 RSI: 00000000ffffdfff RDI: 0000000000000001
+RBP: ffffa91b8007bc88 R08: 0000000000000000 R09: ffffa91b8007bae0
+R10: 00000000ffffdfff R11: ffffffff83a79800 R12: ffff99d695302060
+R13: ffff99d695300900 R14: ffff99d6992e1be0 R15: ffff99d6992e2010
+FS:  0000000000000000(0000) GS:ffff99d6aac00000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 000078fbdba43480 CR3: 000000010e464000 CR4: 00000000001506f0
+Call Trace:
+ <TASK>
+ ? __die_body+0x1f/0x70
+ ? die+0x3d/0x60
+ ? do_trap+0xa4/0x110
+ ? __list_add_valid_or_report+0x5e/0xb0
+ ? do_error_trap+0x6d/0x90
+ ? __list_add_valid_or_report+0x5e/0xb0
+ ? handle_invalid_op+0x30/0x40
+ ? __list_add_valid_or_report+0x5e/0xb0
+ ? exc_invalid_op+0x3c/0x50
+ ? asm_exc_invalid_op+0x16/0x20
+ ? __list_add_valid_or_report+0x5e/0xb0
+ rtw89_ops_add_interface+0x309/0x310 [rtw89_core 7c32b1ee6854761c0321027c8a58c5160e41f48f]
+ drv_add_interface+0x5c/0x130 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc]
+ ieee80211_reconfig+0x241/0x13d0 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc]
+ ? finish_wait+0x3e/0x90
+ ? synchronize_rcu_expedited+0x174/0x260
+ ? sync_rcu_exp_done_unlocked+0x50/0x50
+ ? wake_bit_function+0x40/0x40
+ ieee80211_restart_work+0xf0/0x140 [mac80211 83e989e6e616bd5b4b8a2b0a9f9352a2c385a3bc]
+ process_scheduled_works+0x1e5/0x480
+ worker_thread+0xea/0x1e0
+ kthread+0xdb/0x110
+ ? move_linked_works+0x90/0x90
+ ? kthread_associate_blkcg+0xa0/0xa0
+ ret_from_fork+0x3b/0x50
+ ? kthread_associate_blkcg+0xa0/0xa0
+ ret_from_fork_asm+0x11/0x20
+ </TASK>
+Modules linked in: dm_integrity async_xor xor async_tx lz4 lz4_compress zstd zstd_compress zram zsmalloc rfcomm cmac uinput algif_hash algif_skcipher af_alg btusb btrtl iio_trig_hrtimer industrialio_sw_trigger btmtk industrialio_configfs btbcm btintel uvcvideo videobuf2_vmalloc iio_trig_sysfs videobuf2_memops videobuf2_v4l2 videobuf2_common uvc snd_hda_codec_hdmi veth snd_hda_intel snd_intel_dspcfg acpi_als snd_hda_codec industrialio_triggered_buffer kfifo_buf snd_hwdep industrialio i2c_piix4 snd_hda_core designware_i2s ip6table_nat snd_soc_max98357a xt_MASQUERADE xt_cgroup snd_soc_acp_rt5682_mach fuse rtw89_8922ae(O) rtw89_8922a(O) rtw89_pci(O) rtw89_core(O) 8021q mac80211(O) bluetooth ecdh_generic ecc cfg80211 r8152 mii joydev
+gsmi: Log Shutdown Reason 0x03
+---[ end trace 0000000000000000 ]---
+
+Signed-off-by: Chih-Kang Chang <gary.chang@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240731070506.46100-4-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/mac80211.c |  4 +++-
+ drivers/net/wireless/realtek/rtw89/util.h     | 18 ++++++++++++++++++
+ 2 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
+index 1ec97250e88e5..4fae0bd566f6a 100644
+--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
+@@ -126,7 +126,9 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
+       rtwvif->rtwdev = rtwdev;
+       rtwvif->roc.state = RTW89_ROC_IDLE;
+       rtwvif->offchan = false;
+-      list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
++      if (!rtw89_rtwvif_in_list(rtwdev, rtwvif))
++              list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
++
+       INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work);
+       INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work);
+       rtw89_leave_ps_mode(rtwdev);
+diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h
+index e2ed4565025dd..d4ee9078a4f48 100644
+--- a/drivers/net/wireless/realtek/rtw89/util.h
++++ b/drivers/net/wireless/realtek/rtw89/util.h
+@@ -14,6 +14,24 @@
+ #define rtw89_for_each_rtwvif(rtwdev, rtwvif)                                \
+       list_for_each_entry(rtwvif, &(rtwdev)->rtwvifs_list, list)
++/* Before adding rtwvif to list, we need to check if it already exist, beacase
++ * in some case such as SER L2 happen during WoWLAN flow, calling reconfig
++ * twice cause the list to be added twice.
++ */
++static inline bool rtw89_rtwvif_in_list(struct rtw89_dev *rtwdev,
++                                      struct rtw89_vif *new)
++{
++      struct rtw89_vif *rtwvif;
++
++      lockdep_assert_held(&rtwdev->mutex);
++
++      rtw89_for_each_rtwvif(rtwdev, rtwvif)
++              if (rtwvif == new)
++                      return true;
++
++      return false;
++}
++
+ /* The result of negative dividend and positive divisor is undefined, but it
+  * should be one case of round-down or round-up. So, make it round-down if the
+  * result is round-up.
+-- 
+2.43.0
+
diff --git a/queue-6.10/wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch b/queue-6.10/wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch
new file mode 100644 (file)
index 0000000..87c25da
--- /dev/null
@@ -0,0 +1,53 @@
+From 734cd1e85b41c0dad76090e9a8036a6a59c983c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Aug 2024 15:20:10 +0800
+Subject: wifi: rtw89: correct base HT rate mask for firmware
+
+From: Ping-Ke Shih <pkshih@realtek.com>
+
+[ Upstream commit 45742881f9eee2a4daeb6008e648a460dd3742cd ]
+
+Coverity reported that u8 rx_mask << 24 will become signed 32 bits, which
+casting to unsigned 64 bits will do sign extension. For example,
+putting 0x80000000 (signed 32 bits) to a u64 variable will become
+0xFFFFFFFF_80000000.
+
+The real case we meet is:
+  rx_mask[0...3] = ff ff 00 00
+  ra_mask = 0xffffffff_ff0ff000
+
+After this fix:
+  rx_mask[0...3] = ff ff 00 00
+  ra_mask = 0x00000000_ff0ff000
+
+Fortunately driver does bitwise-AND with incorrect ra_mask and supported
+rates (1ss and 2ss rate only) afterward, so the final rate mask of
+original code is still correct.
+
+Addresses-Coverity-ID: 1504762 ("Unintended sign extension")
+
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20240809072012.84152-5-pkshih@realtek.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/realtek/rtw89/phy.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
+index a82b4c56a6f45..f7c6b019b5be4 100644
+--- a/drivers/net/wireless/realtek/rtw89/phy.c
++++ b/drivers/net/wireless/realtek/rtw89/phy.c
+@@ -352,8 +352,8 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
+               csi_mode = RTW89_RA_RPT_MODE_HT;
+               ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) |
+                          ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) |
+-                         (sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
+-                         (sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
++                         ((u64)sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
++                         ((u64)sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
+               high_rate_masks = rtw89_ra_mask_ht_rates;
+               if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+                       stbc_en = 1;
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-apic-remove-logical-destination-mode-for-64-bit.patch b/queue-6.10/x86-apic-remove-logical-destination-mode-for-64-bit.patch
new file mode 100644 (file)
index 0000000..258118b
--- /dev/null
@@ -0,0 +1,229 @@
+From bc6c84eac6dbd511053fc06ae92bad6cac8ca8a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 28 Jul 2024 13:06:10 +0200
+Subject: x86/apic: Remove logical destination mode for 64-bit
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 838ba7733e4e3a94a928e8d0a058de1811a58621 ]
+
+Logical destination mode of the local APIC is used for systems with up to
+8 CPUs. It has an advantage over physical destination mode as it allows to
+target multiple CPUs at once with IPIs.
+
+That advantage was definitely worth it when systems with up to 8 CPUs
+were state of the art for servers and workstations, but that's history.
+
+Aside of that there are systems which fail to work with logical destination
+mode as the ACPI/DMI quirks show and there are AMD Zen1 systems out there
+which fail when interrupt remapping is enabled as reported by Rob and
+Christian. The latter problem can be cured by firmware updates, but not all
+OEMs distribute the required changes.
+
+Physical destination mode is guaranteed to work because it is the only way
+to get a CPU up and running via the INIT/INIT/STARTUP sequence.
+
+As the number of CPUs keeps increasing, logical destination mode becomes a
+less used code path so there is no real good reason to keep it around.
+
+Therefore remove logical destination mode support for 64-bit and default to
+physical destination mode.
+
+Reported-by: Rob Newcater <rob@durendal.co.uk>
+Reported-by: Christian Heusel <christian@heusel.eu>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Rob Newcater <rob@durendal.co.uk>
+Link: https://lore.kernel.org/all/877cd5u671.ffs@tglx
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/apic.h         |   8 --
+ arch/x86/kernel/apic/apic_flat_64.c | 119 ++--------------------------
+ 2 files changed, 7 insertions(+), 120 deletions(-)
+
+diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
+index 9327eb00e96d0..be2045a18e69b 100644
+--- a/arch/x86/include/asm/apic.h
++++ b/arch/x86/include/asm/apic.h
+@@ -345,20 +345,12 @@ extern struct apic *apic;
+  * APIC drivers are probed based on how they are listed in the .apicdrivers
+  * section. So the order is important and enforced by the ordering
+  * of different apic driver files in the Makefile.
+- *
+- * For the files having two apic drivers, we use apic_drivers()
+- * to enforce the order with in them.
+  */
+ #define apic_driver(sym)                                      \
+       static const struct apic *__apicdrivers_##sym __used            \
+       __aligned(sizeof(struct apic *))                        \
+       __section(".apicdrivers") = { &sym }
+-#define apic_drivers(sym1, sym2)                                      \
+-      static struct apic *__apicdrivers_##sym1##sym2[2] __used        \
+-      __aligned(sizeof(struct apic *))                                \
+-      __section(".apicdrivers") = { &sym1, &sym2 }
+-
+ extern struct apic *__apicdrivers[], *__apicdrivers_end[];
+ /*
+diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
+index f37ad3392fec9..e0308d8c4e6c2 100644
+--- a/arch/x86/kernel/apic/apic_flat_64.c
++++ b/arch/x86/kernel/apic/apic_flat_64.c
+@@ -8,129 +8,25 @@
+  * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+  * James Cleverdon.
+  */
+-#include <linux/cpumask.h>
+ #include <linux/export.h>
+-#include <linux/acpi.h>
+-#include <asm/jailhouse_para.h>
+ #include <asm/apic.h>
+ #include "local.h"
+-static struct apic apic_physflat;
+-static struct apic apic_flat;
+-
+-struct apic *apic __ro_after_init = &apic_flat;
+-EXPORT_SYMBOL_GPL(apic);
+-
+-static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+-{
+-      return 1;
+-}
+-
+-static void _flat_send_IPI_mask(unsigned long mask, int vector)
+-{
+-      unsigned long flags;
+-
+-      local_irq_save(flags);
+-      __default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
+-      local_irq_restore(flags);
+-}
+-
+-static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
+-{
+-      unsigned long mask = cpumask_bits(cpumask)[0];
+-
+-      _flat_send_IPI_mask(mask, vector);
+-}
+-
+-static void
+-flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
+-{
+-      unsigned long mask = cpumask_bits(cpumask)[0];
+-      int cpu = smp_processor_id();
+-
+-      if (cpu < BITS_PER_LONG)
+-              __clear_bit(cpu, &mask);
+-
+-      _flat_send_IPI_mask(mask, vector);
+-}
+-
+-static u32 flat_get_apic_id(u32 x)
++static u32 physflat_get_apic_id(u32 x)
+ {
+       return (x >> 24) & 0xFF;
+ }
+-static int flat_probe(void)
++static int physflat_probe(void)
+ {
+       return 1;
+ }
+-static struct apic apic_flat __ro_after_init = {
+-      .name                           = "flat",
+-      .probe                          = flat_probe,
+-      .acpi_madt_oem_check            = flat_acpi_madt_oem_check,
+-
+-      .dest_mode_logical              = true,
+-
+-      .disable_esr                    = 0,
+-
+-      .init_apic_ldr                  = default_init_apic_ldr,
+-      .cpu_present_to_apicid          = default_cpu_present_to_apicid,
+-
+-      .max_apic_id                    = 0xFE,
+-      .get_apic_id                    = flat_get_apic_id,
+-
+-      .calc_dest_apicid               = apic_flat_calc_apicid,
+-
+-      .send_IPI                       = default_send_IPI_single,
+-      .send_IPI_mask                  = flat_send_IPI_mask,
+-      .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
+-      .send_IPI_allbutself            = default_send_IPI_allbutself,
+-      .send_IPI_all                   = default_send_IPI_all,
+-      .send_IPI_self                  = default_send_IPI_self,
+-      .nmi_to_offline_cpu             = true,
+-
+-      .read                           = native_apic_mem_read,
+-      .write                          = native_apic_mem_write,
+-      .eoi                            = native_apic_mem_eoi,
+-      .icr_read                       = native_apic_icr_read,
+-      .icr_write                      = native_apic_icr_write,
+-      .wait_icr_idle                  = apic_mem_wait_icr_idle,
+-      .safe_wait_icr_idle             = apic_mem_wait_icr_idle_timeout,
+-};
+-
+-/*
+- * Physflat mode is used when there are more than 8 CPUs on a system.
+- * We cannot use logical delivery in this case because the mask
+- * overflows, so use physical mode.
+- */
+ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+ {
+-#ifdef CONFIG_ACPI
+-      /*
+-       * Quirk: some x86_64 machines can only use physical APIC mode
+-       * regardless of how many processors are present (x86_64 ES7000
+-       * is an example).
+-       */
+-      if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+-              (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
+-              printk(KERN_DEBUG "system APIC only can use physical flat");
+-              return 1;
+-      }
+-
+-      if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {
+-              printk(KERN_DEBUG "IBM Summit detected, will use apic physical");
+-              return 1;
+-      }
+-#endif
+-
+-      return 0;
+-}
+-
+-static int physflat_probe(void)
+-{
+-      return apic == &apic_physflat || num_possible_cpus() > 8 || jailhouse_paravirt();
++      return 1;
+ }
+ static struct apic apic_physflat __ro_after_init = {
+@@ -146,7 +42,7 @@ static struct apic apic_physflat __ro_after_init = {
+       .cpu_present_to_apicid          = default_cpu_present_to_apicid,
+       .max_apic_id                    = 0xFE,
+-      .get_apic_id                    = flat_get_apic_id,
++      .get_apic_id                    = physflat_get_apic_id,
+       .calc_dest_apicid               = apic_default_calc_apicid,
+@@ -166,8 +62,7 @@ static struct apic apic_physflat __ro_after_init = {
+       .wait_icr_idle                  = apic_mem_wait_icr_idle,
+       .safe_wait_icr_idle             = apic_mem_wait_icr_idle_timeout,
+ };
++apic_driver(apic_physflat);
+-/*
+- * We need to check for physflat first, so this order is important.
+- */
+-apic_drivers(apic_physflat, apic_flat);
++struct apic *apic __ro_after_init = &apic_physflat;
++EXPORT_SYMBOL_GPL(apic);
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-bugs-add-missing-no_ssb-flag.patch b/queue-6.10/x86-bugs-add-missing-no_ssb-flag.patch
new file mode 100644 (file)
index 0000000..dbe9b99
--- /dev/null
@@ -0,0 +1,46 @@
+From 1247c64e6d9c800b7749ed463d0d5fcb8b11d2b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 12:24:37 -0700
+Subject: x86/bugs: Add missing NO_SSB flag
+
+From: Daniel Sneddon <daniel.sneddon@linux.intel.com>
+
+[ Upstream commit 23e12b54acf621f4f03381dca91cc5f1334f21fd ]
+
+The Moorefield and Lightning Mountain Atom processors are
+missing the NO_SSB flag in the vulnerabilities whitelist.
+This will cause unaffected parts to incorrectly be reported
+as vulnerable. Add the missing flag.
+
+These parts are currently out of service and were verified
+internally with archived documentation that they need the
+NO_SSB flag.
+
+Closes: https://lore.kernel.org/lkml/CAEJ9NQdhh+4GxrtG1DuYgqYhvc0hi-sKZh-2niukJ-MyFLntAA@mail.gmail.com/
+Reported-by: Shanavas.K.S <shanavasks@gmail.com>
+Signed-off-by: Daniel Sneddon <daniel.sneddon@linux.intel.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Link: https://lore.kernel.org/r/20240829192437.4074196-1-daniel.sneddon@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/common.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index d4e539d4e158c..be307c9ef263d 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -1165,8 +1165,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
+       VULNWL_INTEL(INTEL_CORE_YONAH,          NO_SSB),
+-      VULNWL_INTEL(INTEL_ATOM_AIRMONT_MID,    NO_L1TF | MSBDS_ONLY | NO_SWAPGS | NO_ITLB_MULTIHIT),
+-      VULNWL_INTEL(INTEL_ATOM_AIRMONT_NP,     NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
++      VULNWL_INTEL(INTEL_ATOM_AIRMONT_MID,    NO_SSB | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | MSBDS_ONLY),
++      VULNWL_INTEL(INTEL_ATOM_AIRMONT_NP,     NO_SSB | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT),
+       VULNWL_INTEL(INTEL_ATOM_GOLDMONT,       NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+       VULNWL_INTEL(INTEL_ATOM_GOLDMONT_D,     NO_MDS | NO_L1TF | NO_SWAPGS | NO_ITLB_MULTIHIT | NO_MMIO),
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-bugs-fix-handling-when-srso-mitigation-is-disabl.patch b/queue-6.10/x86-bugs-fix-handling-when-srso-mitigation-is-disabl.patch
new file mode 100644 (file)
index 0000000..cf8d130
--- /dev/null
@@ -0,0 +1,69 @@
+From 986dc2c2467899b7682044ebe7521334f2f4cede Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 10:07:11 -0500
+Subject: x86/bugs: Fix handling when SRSO mitigation is disabled
+
+From: David Kaplan <david.kaplan@amd.com>
+
+[ Upstream commit 1dbb6b1495d472806fef1f4c94f5b3e4c89a3c1d ]
+
+When the SRSO mitigation is disabled, either via mitigations=off or
+spec_rstack_overflow=off, the warning about the lack of IBPB-enhancing
+microcode is printed anyway.
+
+This is unnecessary since the user has turned off the mitigation.
+
+  [ bp: Massage, drop SBPB rationale as it doesn't matter because when
+    mitigations are disabled x86_pred_cmd is not being used anyway. ]
+
+Signed-off-by: David Kaplan <david.kaplan@amd.com>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Link: https://lore.kernel.org/r/20240904150711.193022-1-david.kaplan@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/bugs.c | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index b6f927f6c567e..47c84503ad9be 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -2545,10 +2545,9 @@ static void __init srso_select_mitigation(void)
+ {
+       bool has_microcode = boot_cpu_has(X86_FEATURE_IBPB_BRTYPE);
+-      if (cpu_mitigations_off())
+-              return;
+-
+-      if (!boot_cpu_has_bug(X86_BUG_SRSO)) {
++      if (!boot_cpu_has_bug(X86_BUG_SRSO) ||
++          cpu_mitigations_off() ||
++          srso_cmd == SRSO_CMD_OFF) {
+               if (boot_cpu_has(X86_FEATURE_SBPB))
+                       x86_pred_cmd = PRED_CMD_SBPB;
+               return;
+@@ -2579,11 +2578,6 @@ static void __init srso_select_mitigation(void)
+       }
+       switch (srso_cmd) {
+-      case SRSO_CMD_OFF:
+-              if (boot_cpu_has(X86_FEATURE_SBPB))
+-                      x86_pred_cmd = PRED_CMD_SBPB;
+-              return;
+-
+       case SRSO_CMD_MICROCODE:
+               if (has_microcode) {
+                       srso_mitigation = SRSO_MITIGATION_MICROCODE;
+@@ -2637,6 +2631,8 @@ static void __init srso_select_mitigation(void)
+                       pr_err("WARNING: kernel not compiled with MITIGATION_SRSO.\n");
+                 }
+               break;
++      default:
++              break;
+       }
+ out:
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-ioapic-handle-allocation-failures-gracefully.patch b/queue-6.10/x86-ioapic-handle-allocation-failures-gracefully.patch
new file mode 100644 (file)
index 0000000..81aacc5
--- /dev/null
@@ -0,0 +1,153 @@
+From 74433630ece2430c4fc67cd26b6841c9e2d320a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 18:15:34 +0200
+Subject: x86/ioapic: Handle allocation failures gracefully
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 830802a0fea8fb39d3dc9fb7d6b5581e1343eb1f ]
+
+Breno observed panics when using failslab under certain conditions during
+runtime:
+
+   can not alloc irq_pin_list (-1,0,20)
+   Kernel panic - not syncing: IO-APIC: failed to add irq-pin. Can not proceed
+
+   panic+0x4e9/0x590
+   mp_irqdomain_alloc+0x9ab/0xa80
+   irq_domain_alloc_irqs_locked+0x25d/0x8d0
+   __irq_domain_alloc_irqs+0x80/0x110
+   mp_map_pin_to_irq+0x645/0x890
+   acpi_register_gsi_ioapic+0xe6/0x150
+   hpet_open+0x313/0x480
+
+That's a pointless panic which is a leftover of the historic IO/APIC code
+which panic'ed during early boot when the interrupt allocation failed.
+
+The only place which might justify panic is the PIT/HPET timer_check() code
+which tries to figure out whether the timer interrupt is delivered through
+the IO/APIC. But that code does not require to handle interrupt allocation
+failures. If the interrupt cannot be allocated then timer delivery fails
+and it either panics due to that or falls back to legacy mode.
+
+Cure this by removing the panic wrapper around __add_pin_to_irq_node() and
+making mp_irqdomain_alloc() aware of the failure condition and handle it as
+any other failure in this function gracefully.
+
+Reported-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Breno Leitao <leitao@debian.org>
+Tested-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
+Link: https://lore.kernel.org/all/ZqfJmUF8sXIyuSHN@gmail.com
+Link: https://lore.kernel.org/all/20240802155440.275200843@linutronix.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/apic/io_apic.c | 46 ++++++++++++++++------------------
+ 1 file changed, 22 insertions(+), 24 deletions(-)
+
+diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
+index 477b740b2f267..d1ec1dcb637af 100644
+--- a/arch/x86/kernel/apic/io_apic.c
++++ b/arch/x86/kernel/apic/io_apic.c
+@@ -352,27 +352,26 @@ static void ioapic_mask_entry(int apic, int pin)
+  * shared ISA-space IRQs, so we have to support them. We are super
+  * fast in the common case, and fast for shared ISA-space IRQs.
+  */
+-static int __add_pin_to_irq_node(struct mp_chip_data *data,
+-                               int node, int apic, int pin)
++static bool add_pin_to_irq_node(struct mp_chip_data *data, int node, int apic, int pin)
+ {
+       struct irq_pin_list *entry;
+-      /* don't allow duplicates */
+-      for_each_irq_pin(entry, data->irq_2_pin)
++      /* Don't allow duplicates */
++      for_each_irq_pin(entry, data->irq_2_pin) {
+               if (entry->apic == apic && entry->pin == pin)
+-                      return 0;
++                      return true;
++      }
+       entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
+       if (!entry) {
+-              pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
+-                     node, apic, pin);
+-              return -ENOMEM;
++              pr_err("Cannot allocate irq_pin_list (%d,%d,%d)\n", node, apic, pin);
++              return false;
+       }
++
+       entry->apic = apic;
+       entry->pin = pin;
+       list_add_tail(&entry->list, &data->irq_2_pin);
+-
+-      return 0;
++      return true;
+ }
+ static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
+@@ -387,13 +386,6 @@ static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
+               }
+ }
+-static void add_pin_to_irq_node(struct mp_chip_data *data,
+-                              int node, int apic, int pin)
+-{
+-      if (__add_pin_to_irq_node(data, node, apic, pin))
+-              panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
+-}
+-
+ /*
+  * Reroute an IRQ to a different pin.
+  */
+@@ -1002,8 +994,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
+       if (irq_data && irq_data->parent_data) {
+               if (!mp_check_pin_attr(irq, info))
+                       return -EBUSY;
+-              if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic,
+-                                        info->ioapic.pin))
++              if (!add_pin_to_irq_node(irq_data->chip_data, node, ioapic, info->ioapic.pin))
+                       return -ENOMEM;
+       } else {
+               info->flags |= X86_IRQ_ALLOC_LEGACY;
+@@ -3017,10 +3008,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+               return -ENOMEM;
+       ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+-      if (ret < 0) {
+-              kfree(data);
+-              return ret;
+-      }
++      if (ret < 0)
++              goto free_data;
+       INIT_LIST_HEAD(&data->irq_2_pin);
+       irq_data->hwirq = info->ioapic.pin;
+@@ -3029,7 +3018,10 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+       irq_data->chip_data = data;
+       mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
+-      add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
++      if (!add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin)) {
++              ret = -ENOMEM;
++              goto free_irqs;
++      }
+       mp_preconfigure_entry(data);
+       mp_register_handler(virq, data->is_level);
+@@ -3044,6 +3036,12 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+                   ioapic, mpc_ioapic_id(ioapic), pin, virq,
+                   data->is_level, data->active_low);
+       return 0;
++
++free_irqs:
++      irq_domain_free_irqs_parent(domain, virq, nr_irqs);
++free_data:
++      kfree(data);
++      return ret;
+ }
+ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-kexec-add-efi-config-table-identity-mapping-for-.patch b/queue-6.10/x86-kexec-add-efi-config-table-identity-mapping-for-.patch
new file mode 100644 (file)
index 0000000..3fcc8f4
--- /dev/null
@@ -0,0 +1,116 @@
+From e399b48d8b623fd1f4970d915351f766915b170d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Jul 2024 16:31:20 -0500
+Subject: x86/kexec: Add EFI config table identity mapping for kexec kernel
+
+From: Tao Liu <ltao@redhat.com>
+
+[ Upstream commit 5760929f6545c651682de3c2c6c6786816b17bb1 ]
+
+A kexec kernel boot failure is sometimes observed on AMD CPUs due to an
+unmapped EFI config table array.  This can be seen when "nogbpages" is on
+the kernel command line, and has been observed as a full BIOS reboot rather
+than a successful kexec.
+
+This was also the cause of reported regressions attributed to Commit
+7143c5f4cf20 ("x86/mm/ident_map: Use gbpages only where full GB page should
+be mapped.") which was subsequently reverted.
+
+To avoid this page fault, explicitly include the EFI config table array in
+the kexec identity map.
+
+Further explanation:
+
+The following 2 commits caused the EFI config table array to be
+accessed when enabling sev at kernel startup.
+
+    commit ec1c66af3a30 ("x86/compressed/64: Detect/setup SEV/SME features
+                          earlier during boot")
+    commit c01fce9cef84 ("x86/compressed: Add SEV-SNP feature
+                          detection/setup")
+
+This is in the code that examines whether SEV should be enabled or not, so
+it can even affect systems that are not SEV capable.
+
+This may result in a page fault if the EFI config table array's address is
+unmapped. Since the page fault occurs before the new kernel establishes its
+own identity map and page fault routines, it is unrecoverable and kexec
+fails.
+
+Most often, this problem is not seen because the EFI config table array
+gets included in the map by the luck of being placed at a memory address
+close enough to other memory areas that *are* included in the map created
+by kexec.
+
+Both the "nogbpages" command line option and the "use gpbages only where
+full GB page should be mapped" change greatly reduce the chance of being
+included in the map by luck, which is why the problem appears.
+
+Signed-off-by: Tao Liu <ltao@redhat.com>
+Signed-off-by: Steve Wahl <steve.wahl@hpe.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Pavin Joseph <me@pavinjoseph.com>
+Tested-by: Sarah Brofeldt <srhb@dbc.dk>
+Tested-by: Eric Hagberg <ehagberg@gmail.com>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Link: https://lore.kernel.org/all/20240717213121.3064030-2-steve.wahl@hpe.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/machine_kexec_64.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
+index cc0f7f70b17ba..9c9ac606893e9 100644
+--- a/arch/x86/kernel/machine_kexec_64.c
++++ b/arch/x86/kernel/machine_kexec_64.c
+@@ -28,6 +28,7 @@
+ #include <asm/setup.h>
+ #include <asm/set_memory.h>
+ #include <asm/cpu.h>
++#include <asm/efi.h>
+ #ifdef CONFIG_ACPI
+ /*
+@@ -87,6 +88,8 @@ map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p)
+ {
+ #ifdef CONFIG_EFI
+       unsigned long mstart, mend;
++      void *kaddr;
++      int ret;
+       if (!efi_enabled(EFI_BOOT))
+               return 0;
+@@ -102,6 +105,30 @@ map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p)
+       if (!mstart)
+               return 0;
++      ret = kernel_ident_mapping_init(info, level4p, mstart, mend);
++      if (ret)
++              return ret;
++
++      kaddr = memremap(mstart, mend - mstart, MEMREMAP_WB);
++      if (!kaddr) {
++              pr_err("Could not map UEFI system table\n");
++              return -ENOMEM;
++      }
++
++      mstart = efi_config_table;
++
++      if (efi_enabled(EFI_64BIT)) {
++              efi_system_table_64_t *stbl = (efi_system_table_64_t *)kaddr;
++
++              mend = mstart + sizeof(efi_config_table_64_t) * stbl->nr_tables;
++      } else {
++              efi_system_table_32_t *stbl = (efi_system_table_32_t *)kaddr;
++
++              mend = mstart + sizeof(efi_config_table_32_t) * stbl->nr_tables;
++      }
++
++      memunmap(kaddr);
++
+       return kernel_ident_mapping_init(info, level4p, mstart, mend);
+ #endif
+       return 0;
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-mm-ident_map-use-gbpages-only-where-full-gb-page.patch b/queue-6.10/x86-mm-ident_map-use-gbpages-only-where-full-gb-page.patch
new file mode 100644 (file)
index 0000000..8d53c7c
--- /dev/null
@@ -0,0 +1,83 @@
+From 82b519ecb2fd30fb62d54b2fd0a31bd750389840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Jul 2024 16:31:21 -0500
+Subject: x86/mm/ident_map: Use gbpages only where full GB page should be
+ mapped.
+
+From: Steve Wahl <steve.wahl@hpe.com>
+
+[ Upstream commit cc31744a294584a36bf764a0ffa3255a8e69f036 ]
+
+When ident_pud_init() uses only GB pages to create identity maps, large
+ranges of addresses not actually requested can be included in the resulting
+table; a 4K request will map a full GB.  This can include a lot of extra
+address space past that requested, including areas marked reserved by the
+BIOS.  That allows processor speculation into reserved regions, that on UV
+systems can cause system halts.
+
+Only use GB pages when map creation requests include the full GB page of
+space.  Fall back to using smaller 2M pages when only portions of a GB page
+are included in the request.
+
+No attempt is made to coalesce mapping requests. If a request requires a
+map entry at the 2M (pmd) level, subsequent mapping requests within the
+same 1G region will also be at the pmd level, even if adjacent or
+overlapping such requests could have been combined to map a full GB page.
+Existing usage starts with larger regions and then adds smaller regions, so
+this should not have any great consequence.
+
+Signed-off-by: Steve Wahl <steve.wahl@hpe.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Pavin Joseph <me@pavinjoseph.com>
+Tested-by: Sarah Brofeldt <srhb@dbc.dk>
+Tested-by: Eric Hagberg <ehagberg@gmail.com>
+Link: https://lore.kernel.org/all/20240717213121.3064030-3-steve.wahl@hpe.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/ident_map.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/mm/ident_map.c b/arch/x86/mm/ident_map.c
+index 968d7005f4a72..a204a332c71fc 100644
+--- a/arch/x86/mm/ident_map.c
++++ b/arch/x86/mm/ident_map.c
+@@ -26,18 +26,31 @@ static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
+       for (; addr < end; addr = next) {
+               pud_t *pud = pud_page + pud_index(addr);
+               pmd_t *pmd;
++              bool use_gbpage;
+               next = (addr & PUD_MASK) + PUD_SIZE;
+               if (next > end)
+                       next = end;
+-              if (info->direct_gbpages) {
+-                      pud_t pudval;
++              /* if this is already a gbpage, this portion is already mapped */
++              if (pud_leaf(*pud))
++                      continue;
++
++              /* Is using a gbpage allowed? */
++              use_gbpage = info->direct_gbpages;
+-                      if (pud_present(*pud))
+-                              continue;
++              /* Don't use gbpage if it maps more than the requested region. */
++              /* at the begining: */
++              use_gbpage &= ((addr & ~PUD_MASK) == 0);
++              /* ... or at the end: */
++              use_gbpage &= ((next & ~PUD_MASK) == 0);
++
++              /* Never overwrite existing mappings */
++              use_gbpage &= !pud_present(*pud);
++
++              if (use_gbpage) {
++                      pud_t pudval;
+-                      addr &= PUD_MASK;
+                       pudval = __pud((addr - info->offset) | info->page_flag);
+                       set_pud(pud, pudval);
+                       continue;
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch b/queue-6.10/x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch
new file mode 100644 (file)
index 0000000..73ec496
--- /dev/null
@@ -0,0 +1,128 @@
+From a9e240fd744a39556fff7f3dc083d4a4bae11caf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 06:13:14 +0000
+Subject: x86/pkeys: Add PKRU as a parameter in signal handling functions
+
+From: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+
+[ Upstream commit 24cf2bc982ffe02aeffb4a3885c71751a2c7023b ]
+
+Assume there's a multithreaded application that runs untrusted user
+code. Each thread has its stack/code protected by a non-zero PKEY, and the
+PKRU register is set up such that only that particular non-zero PKEY is
+enabled. Each thread also sets up an alternate signal stack to handle
+signals, which is protected by PKEY zero. The PKEYs man page documents that
+the PKRU will be reset to init_pkru when the signal handler is invoked,
+which means that PKEY zero access will be enabled.  But this reset happens
+after the kernel attempts to push fpu state to the alternate stack, which
+is not (yet) accessible by the kernel, which leads to a new SIGSEGV being
+sent to the application, terminating it.
+
+Enabling both the non-zero PKEY (for the thread) and PKEY zero in
+userspace will not work for this use case. It cannot have the alt stack
+writeable by all - the rationale here is that the code running in that
+thread (using a non-zero PKEY) is untrusted and should not have access
+to the alternate signal stack (that uses PKEY zero), to prevent the
+return address of a function from being changed. The expectation is that
+kernel should be able to set up the alternate signal stack and deliver
+the signal to the application even if PKEY zero is explicitly disabled
+by the application. The signal handler accessibility should not be
+dictated by whatever PKRU value the thread sets up.
+
+The PKRU register is managed by XSAVE, which means the sigframe contents
+must match the register contents - which is not the case here. It's
+required that the signal frame contains the user-defined PKRU value (so
+that it is restored correctly from sigcontext) but the actual register must
+be reset to init_pkru so that the alt stack is accessible and the signal
+can be delivered to the application. It seems that the proper fix here
+would be to remove PKRU from the XSAVE framework and manage it separately,
+which is quite complicated. As a workaround, do this:
+
+        orig_pkru = rdpkru();
+        wrpkru(orig_pkru & init_pkru_value);
+        xsave_to_user_sigframe();
+        put_user(pkru_sigframe_addr, orig_pkru)
+
+In preparation for writing PKRU to sigframe, pass PKRU as an additional
+parameter down the call chain from get_sigframe().
+
+No functional change.
+
+Signed-off-by: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20240802061318.2140081-2-aruna.ramakrishna@oracle.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/fpu/signal.h | 2 +-
+ arch/x86/kernel/fpu/signal.c      | 6 +++---
+ arch/x86/kernel/signal.c          | 3 ++-
+ 3 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
+index 611fa41711aff..eccc75bc9c4f3 100644
+--- a/arch/x86/include/asm/fpu/signal.h
++++ b/arch/x86/include/asm/fpu/signal.h
+@@ -29,7 +29,7 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
+ unsigned long fpu__get_fpstate_size(void);
+-extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size);
++extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size, u32 pkru);
+ extern void fpu__clear_user_states(struct fpu *fpu);
+ extern bool fpu__restore_sig(void __user *buf, int ia32_frame);
+diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
+index 247f2225aa9f3..2b3b9e140dd41 100644
+--- a/arch/x86/kernel/fpu/signal.c
++++ b/arch/x86/kernel/fpu/signal.c
+@@ -156,7 +156,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame,
+       return !err;
+ }
+-static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
++static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, u32 pkru)
+ {
+       if (use_xsave())
+               return xsave_to_user_sigframe(buf);
+@@ -185,7 +185,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
+  * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
+  * indicating the absence/presence of the extended state to the user.
+  */
+-bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
++bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size, u32 pkru)
+ {
+       struct task_struct *tsk = current;
+       struct fpstate *fpstate = tsk->thread.fpu.fpstate;
+@@ -228,7 +228,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
+               fpregs_restore_userregs();
+       pagefault_disable();
+-      ret = copy_fpregs_to_sigframe(buf_fx);
++      ret = copy_fpregs_to_sigframe(buf_fx, pkru);
+       pagefault_enable();
+       fpregs_unlock();
+diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
+index 31b6f5dddfc27..1f1e8e0ac5a34 100644
+--- a/arch/x86/kernel/signal.c
++++ b/arch/x86/kernel/signal.c
+@@ -84,6 +84,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
+       unsigned long math_size = 0;
+       unsigned long sp = regs->sp;
+       unsigned long buf_fx = 0;
++      u32 pkru = read_pkru();
+       /* redzone */
+       if (!ia32_frame)
+@@ -139,7 +140,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
+       }
+       /* save i387 and extended state */
+-      if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size))
++      if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size, pkru))
+               return (void __user *)-1L;
+       return (void __user *)sp;
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-pkeys-restore-altstack-access-in-sigreturn.patch b/queue-6.10/x86-pkeys-restore-altstack-access-in-sigreturn.patch
new file mode 100644 (file)
index 0000000..1464abc
--- /dev/null
@@ -0,0 +1,53 @@
+From dd65e95f89bc8480375ad65f989670f175e34941 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Aug 2024 06:13:17 +0000
+Subject: x86/pkeys: Restore altstack access in sigreturn()
+
+From: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+
+[ Upstream commit d10b554919d4cc8fa8fe2e95b57ad2624728c8e4 ]
+
+A process can disable access to the alternate signal stack by not
+enabling the altstack's PKEY in the PKRU register.
+
+Nevertheless, the kernel updates the PKRU temporarily for signal
+handling. However, in sigreturn(), restore_sigcontext() will restore the
+PKRU to the user-defined PKRU value.
+
+This will cause restore_altstack() to fail with a SIGSEGV as it needs read
+access to the altstack which is prohibited by the user-defined PKRU value.
+
+Fix this by restoring altstack before restoring PKRU.
+
+Signed-off-by: Aruna Ramakrishna <aruna.ramakrishna@oracle.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20240802061318.2140081-5-aruna.ramakrishna@oracle.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/signal_64.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
+index 8a94053c54446..ee9453891901b 100644
+--- a/arch/x86/kernel/signal_64.c
++++ b/arch/x86/kernel/signal_64.c
+@@ -260,13 +260,13 @@ SYSCALL_DEFINE0(rt_sigreturn)
+       set_current_blocked(&set);
+-      if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
++      if (restore_altstack(&frame->uc.uc_stack))
+               goto badframe;
+-      if (restore_signal_shadow_stack())
++      if (!restore_sigcontext(regs, &frame->uc.uc_mcontext, uc_flags))
+               goto badframe;
+-      if (restore_altstack(&frame->uc.uc_stack))
++      if (restore_signal_shadow_stack())
+               goto badframe;
+       return regs->ax;
+-- 
+2.43.0
+
diff --git a/queue-6.10/x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch b/queue-6.10/x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch
new file mode 100644 (file)
index 0000000..7afa90b
--- /dev/null
@@ -0,0 +1,71 @@
+From 2981a1b5973d0439ff4c0188563f420e0422ca23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Jul 2024 13:22:06 -0700
+Subject: x86/syscall: Avoid memcpy() for ia32 syscall_get_arguments()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kees Cook <kees@kernel.org>
+
+[ Upstream commit d19d638b1e6cf746263ef60b7d0dee0204d8216a ]
+
+Modern (fortified) memcpy() prefers to avoid writing (or reading) beyond
+the end of the addressed destination (or source) struct member:
+
+In function ‘fortify_memcpy_chk’,
+    inlined from ‘syscall_get_arguments’ at ./arch/x86/include/asm/syscall.h:85:2,
+    inlined from ‘populate_seccomp_data’ at kernel/seccomp.c:258:2,
+    inlined from ‘__seccomp_filter’ at kernel/seccomp.c:1231:3:
+./include/linux/fortify-string.h:580:25: error: call to ‘__read_overflow2_field’ declared with attribute warning: detected read beyond size of field (2nd parameter); maybe use struct_group()? [-Werror=attribute-warning]
+  580 |                         __read_overflow2_field(q_size_field, size);
+      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As already done for x86_64 and compat mode, do not use memcpy() to
+extract syscall arguments from struct pt_regs but rather just perform
+direct assignments. Binary output differences are negligible, and actually
+ends up using less stack space:
+
+-       sub    $0x84,%esp
++       sub    $0x6c,%esp
+
+and less text size:
+
+   text    data     bss     dec     hex filename
+  10794     252       0   11046    2b26 gcc-32b/kernel/seccomp.o.stock
+  10714     252       0   10966    2ad6 gcc-32b/kernel/seccomp.o.after
+
+Closes: https://lore.kernel.org/lkml/9b69fb14-df89-4677-9c82-056ea9e706f5@gmail.com/
+Reported-by: Mirsad Todorovac <mtodorovac69@gmail.com>
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
+Reviewed-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Tested-by: Mirsad Todorovac <mtodorovac69@gmail.com>
+Link: https://lore.kernel.org/all/20240708202202.work.477-kees%40kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/syscall.h | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
+index 2fc7bc3863ff6..7c488ff0c7641 100644
+--- a/arch/x86/include/asm/syscall.h
++++ b/arch/x86/include/asm/syscall.h
+@@ -82,7 +82,12 @@ static inline void syscall_get_arguments(struct task_struct *task,
+                                        struct pt_regs *regs,
+                                        unsigned long *args)
+ {
+-      memcpy(args, &regs->bx, 6 * sizeof(args[0]));
++      args[0] = regs->bx;
++      args[1] = regs->cx;
++      args[2] = regs->dx;
++      args[3] = regs->si;
++      args[4] = regs->di;
++      args[5] = regs->bp;
+ }
+ static inline int syscall_get_arch(struct task_struct *task)
+-- 
+2.43.0
+