From 6915072f65335ea928f2dfb5fdefb3b4d1ece5d7 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sun, 6 Oct 2024 11:11:22 -0400 Subject: [PATCH] Fixes for 6.6 Signed-off-by: Sasha Levin --- ...pport-for-setting-epp-register-in-ff.patch | 74 + ...elease-locks-during-operation-region.patch | 166 + ...pi-pad-fix-crash-in-exit_round_robin.patch | 96 + ...orce_vendor-quirk-for-panasonic-toug.patch | 45 + ...l-return-of-acpi_allocate_zeroed-in-.patch | 41 + ...y-leak-if-acpi_ps_get_next_field-fai.patch | 90 + ...y-leak-if-acpi_ps_get_next_namepath-.patch | 55 + ...ca-iasl-handle-empty-connection_node.patch | 36 + ...sihpi-fix-potential-oob-array-access.patch | 39 + ...break-infinite-midi-input-flush-loop.patch | 60 + ...dd-input-value-sanity-checks-for-sta.patch | 140 + ...dio-add-logitech-audio-profile-quirk.patch | 40 + ...efine-macros-for-quirk-table-entries.patch | 111 + ...eplace-complex-quirk-lines-with-macr.patch | 4000 +++++++++++++++++ ...-support-multiple-control-interfaces.patch | 659 +++ ...a883x-handle-reading-version-failure.patch | 72 + ...rworks-do-not-use-the-term-blacklist.patch | 65 + ...l-rename-sil_blacklist-to-sil_quirks.patch | 61 + ..._iocost-fix-more-out-of-bound-shifts.patch | 80 + ...set-msft-ext-address-filter-quirk-fo.patch | 42 + ...add-realtek-rtl8852c-support-id-0x04.patch | 67 + ...aximum-length-of-version-string-by-1.patch | 42 + ...nter-returned-by-iter-next-method-va.patch | 108 + ...fined-behavior-caused-by-shifting-in.patch | 55 + ...x-undefined-behavior-in-qsort-null-0.patch | 57 + ...d-call-to-do_set_data_bittiming-call.patch | 173 + ...mounting-v1-hierarchies-without-cont.patch | 71 + ...coredump-standartize-and-fix-logging.patch | 178 + .../crypto-octeontx-fix-authenc-setkey.patch | 408 ++ .../crypto-octeontx2-fix-authenc-setkey.patch | 394 ++ ...ot-call-crypto_alloc_tfm-during-regi.patch | 249 + ...6-add-parentheses-around-macros-sing.patch | 92 + ..._spe-use-perf_allow_kernel-for-permi.patch | 115 + ...add-null-check-for-afb-in-amdgpu_dm_.patch | 54 + ...add-null-check-for-top_pipe_to_progr.patch | 52 + ...avoid-overflow-assignment-in-link_dp.patch | 71 + ...check-link_res-hpo_dp_link_enc-befor.patch | 54 + ...check-null-pointers-before-using-dc-.patch | 46 + ...y-check-stream-before-comparing-them.patch | 41 + ...fix-double-free-issue-during-amdgpu-.patch | 79 + ...fix-index-out-of-bounds-in-dcn30-col.patch | 54 + ...fix-index-out-of-bounds-in-dcn30-deg.patch | 55 + ...fix-index-out-of-bounds-in-degamma-h.patch | 55 + ...handle-null-stream_status-in-planes_.patch | 52 + ...initialize-get_bytes_per_element-s-d.patch | 55 + ...e-the-fw_info-is-not-null-before-usi.patch | 36 + .../drm-amdgpu-add-raven1-gfxoff-quirk.patch | 35 + ...amdgpu-block-mmr_read-ioctl-in-reset.patch | 111 + ...low-multiple-bo_handles-chunks-in-on.patch | 49 + ...dgpu-enable-gfxoff-quirk-on-hp-705g4.patch | 38 + ...nchecked-return-value-warning-for-am.patch | 72 + ...-use-rlc-safe-mode-for-soft-recovery.patch | 35 + ...-use-rlc-safe-mode-for-soft-recovery.patch | 35 + ...-use-rlc-safe-mode-for-soft-recovery.patch | 35 + ...d_free_gtt_mem-clear-the-correct-poi.patch | 165 + ...-resource-leak-in-criu-restore-queue.patch | 35 + ...ssign-msm_gpu-pdev-earlier-to-avoid-.patch | 61 + ...low-null-data-in-devcoredump-printer.patch | 144 + ...handle-unknown-family-in-r100_cp_ini.patch | 140 + ...e-after-free-issues-with-crtc-and-pl.patch | 254 ++ ...et-plane-transparency-after-plane-di.patch | 38 + ...failing-the-system-during-pm_suspend.patch | 104 + ...use-after-free-in-ext4_ext_show_leaf.patch | 94 + ...et-sb_rdonly-after-filesystem-errors.patch | 56 + ...rch_dir-should-return-a-proper-error.patch | 86 + ...sem-unlock-order-in-ext4_ind_migrate.patch | 55 + ...ster-sysfs-groups-through-driver-cor.patch | 73 + ...possible-use-after-free-in-pxafb_tas.patch | 59 + ...battery-for-all-elan-i2c-hid-devices.patch | 126 + ...dd-support-for-thinkpad-x12-gen-2-kb.patch | 54 + ...dd-g15cf-to-asus-wmi-monitoring-list.patch | 39 + ...allocation-of-memory-in-ice_sched_ad.patch | 61 + ...ost-direct-i-o-invalidate-race-in-io.patch | 49 + ...s-reserve-a-domain-id-for-identity-s.patch | 44 + ...otential-lockup-if-qi_submit_sync-ca.patch | 128 + ...in_dev-earlier-for-ioctl-siocsifaddr.patch | 52 + ...dscp-bits-and-ecn-bits-in-netlink_fi.patch | 50 + ...fidx-greater-than-num-leaves-per-dma.patch | 52 + queue-6.6/jfs-fix-uaf-in-dbfreebits.patch | 117 + ...-value-access-of-new_ea-in-ea_buffer.patch | 57 + ...an-shift-out-of-bounds-in-dbfindbits.patch | 35 + ...smbd-add-refcnt-to-ksmbd_conn-struct.patch | 245 + ...id-warning-about-potential-string-tr.patch | 79 + ...icon-hip04-fix-of-node-leak-in-probe.patch | 36 + ...s_dsaf_mac-fix-of-node-leak-in-hns_m.patch | 36 + ...n-hns_mdio-fix-of-node-leak-in-probe.patch | 36 + ...2-increase-size-of-queue_name-buffer.patch | 58 + ...tently-use-rcu_replace_pointer-in-ta.patch | 42 + ...ack-prevent-uaf-in-xenvif_flush_hash.patch | 50 + ...ensure-clean-state-on-setup-failures.patch | 106 + ...e-irqf_no_autoen-flag-in-request_irq.patch | 46 + ...actual-buffer-size-in-of_irq_parse_o.patch | 39 + ...perf-fix-event_function_call-locking.patch | 63 + ...issing-caller-address-in-stack-trace.patch | 197 + ...-x86-lenovo-ymc-ignore-the-0x0-state.patch | 46 + ...ouchscreen_dmi-add-nanote-next-quirk.patch | 69 + ...stb-do-not-go-into-infinite-loop-if-.patch | 39 + ...use-correct-data-types-from-pseries_.patch | 157 + ...ig-param-to-block-forcing-mem-writes.patch | 200 + ...-clear-error-when-async-specified-wi.patch | 47 + ...arrange-order-of-struct-aac_srb_unit.patch | 112 + ...-prlo-handling-in-direct-attached-to.patch | 113 + ...tialize-buffer-for-msg-in-and-status.patch | 50 + ...si-smartpqi-correct-stream-detection.patch | 50 + ...olibc-avoid-passing-null-to-printf-s.patch | 52 + queue-6.6/series | 131 + ...g-fin_wait2-when-trying-to-find-port.patch | 82 + ...-guard-against-string-buffer-overrun.patch | 53 + ...erpc-limit-stack-protector-workaroun.patch | 41 + ...-protect-against-faulty-max-subleaf-.patch | 68 + ...array-out-of-bound-access-in-soc-sta.patch | 43 + ...array-out-of-bound-access-in-soc-sta.patch | 43 + ...ossible-integer-overflow-in-ath9k_ge.patch | 47 + ...se-__skb_set_length-for-resetting-ur.patch | 59 + ...et-correct-chandef-when-starting-cac.patch | 77 + ...i-mvm-avoid-null-pointer-dereference.patch | 76 + ...i-mvm-drop-wrong-sta-selection-in-tx.patch | 64 + ...fi-mvm-fix-a-race-in-scan-abort-flow.patch | 153 + ...wlwifi-mvm-use-correct-key-iteration.patch | 61 + ...ifi-mac80211-fix-rcu-list-iterations.patch | 84 + ...-add-dummy-hw-offload-of-ieee-802.11.patch | 62 + ...-disable-tx-worker-during-tx-ba-sess.patch | 47 + ...-hold-dev-mt76.mutex-while-disabling.patch | 41 + ...-memcpy-field-spanning-write-warning.patch | 62 + .../wifi-rtw88-select-want_dev_coredump.patch | 35 + ...-to-add-interface-to-list-twice-when.patch | 124 + ...rrect-base-ht-rate-mask-for-firmware.patch | 53 + ...andle-allocation-failures-gracefully.patch | 153 + ...i-config-table-identity-mapping-for-.patch | 116 + ...ru-as-a-parameter-in-signal-handling.patch | 128 + ...restore-altstack-access-in-sigreturn.patch | 53 + ...d-memcpy-for-ia32-syscall_get_argume.patch | 71 + 132 files changed, 15318 insertions(+) create mode 100644 queue-6.6/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch create mode 100644 queue-6.6/acpi-ec-do-not-release-locks-during-operation-region.patch create mode 100644 queue-6.6/acpi-pad-fix-crash-in-exit_round_robin.patch create mode 100644 queue-6.6/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch create mode 100644 queue-6.6/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch create mode 100644 queue-6.6/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch create mode 100644 queue-6.6/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch create mode 100644 queue-6.6/acpica-iasl-handle-empty-connection_node.patch create mode 100644 queue-6.6/alsa-asihpi-fix-potential-oob-array-access.patch create mode 100644 queue-6.6/alsa-hdsp-break-infinite-midi-input-flush-loop.patch create mode 100644 queue-6.6/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch create mode 100644 queue-6.6/alsa-usb-audio-add-logitech-audio-profile-quirk.patch create mode 100644 queue-6.6/alsa-usb-audio-define-macros-for-quirk-table-entries.patch create mode 100644 queue-6.6/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch create mode 100644 queue-6.6/alsa-usb-audio-support-multiple-control-interfaces.patch create mode 100644 queue-6.6/asoc-codecs-wsa883x-handle-reading-version-failure.patch create mode 100644 queue-6.6/ata-pata_serverworks-do-not-use-the-term-blacklist.patch create mode 100644 queue-6.6/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch create mode 100644 queue-6.6/blk_iocost-fix-more-out-of-bound-shifts.patch create mode 100644 queue-6.6/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch create mode 100644 queue-6.6/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch create mode 100644 queue-6.6/bnxt_en-extend-maximum-length-of-version-string-by-1.patch create mode 100644 queue-6.6/bpf-make-the-pointer-returned-by-iter-next-method-va.patch create mode 100644 queue-6.6/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch create mode 100644 queue-6.6/bpftool-fix-undefined-behavior-in-qsort-null-0.patch create mode 100644 queue-6.6/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch create mode 100644 queue-6.6/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch create mode 100644 queue-6.6/coredump-standartize-and-fix-logging.patch create mode 100644 queue-6.6/crypto-octeontx-fix-authenc-setkey.patch create mode 100644 queue-6.6/crypto-octeontx2-fix-authenc-setkey.patch create mode 100644 queue-6.6/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch create mode 100644 queue-6.6/crypto-x86-sha256-add-parentheses-around-macros-sing.patch create mode 100644 queue-6.6/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch create mode 100644 queue-6.6/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch create mode 100644 queue-6.6/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch create mode 100644 queue-6.6/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch create mode 100644 queue-6.6/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch create mode 100644 queue-6.6/drm-amd-display-check-null-pointers-before-using-dc-.patch create mode 100644 queue-6.6/drm-amd-display-check-stream-before-comparing-them.patch create mode 100644 queue-6.6/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch create mode 100644 queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch create mode 100644 queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch create mode 100644 queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch create mode 100644 queue-6.6/drm-amd-display-handle-null-stream_status-in-planes_.patch create mode 100644 queue-6.6/drm-amd-display-initialize-get_bytes_per_element-s-d.patch create mode 100644 queue-6.6/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch create mode 100644 queue-6.6/drm-amdgpu-add-raven1-gfxoff-quirk.patch create mode 100644 queue-6.6/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch create mode 100644 queue-6.6/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch create mode 100644 queue-6.6/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch create mode 100644 queue-6.6/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch create mode 100644 queue-6.6/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch create mode 100644 queue-6.6/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch create mode 100644 queue-6.6/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch create mode 100644 queue-6.6/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch create mode 100644 queue-6.6/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch create mode 100644 queue-6.6/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch create mode 100644 queue-6.6/drm-printer-allow-null-data-in-devcoredump-printer.patch create mode 100644 queue-6.6/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch create mode 100644 queue-6.6/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch create mode 100644 queue-6.6/drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch create mode 100644 queue-6.6/e1000e-avoid-failing-the-system-during-pm_suspend.patch create mode 100644 queue-6.6/ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch create mode 100644 queue-6.6/ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch create mode 100644 queue-6.6/ext4-ext4_search_dir-should-return-a-proper-error.patch create mode 100644 queue-6.6/ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch create mode 100644 queue-6.6/fbdev-efifb-register-sysfs-groups-through-driver-cor.patch create mode 100644 queue-6.6/fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch create mode 100644 queue-6.6/hid-ignore-battery-for-all-elan-i2c-hid-devices.patch create mode 100644 queue-6.6/hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch create mode 100644 queue-6.6/hwmon-nct6775-add-g15cf-to-asus-wmi-monitoring-list.patch create mode 100644 queue-6.6/ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch create mode 100644 queue-6.6/iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch create mode 100644 queue-6.6/iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch create mode 100644 queue-6.6/iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch create mode 100644 queue-6.6/ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch create mode 100644 queue-6.6/ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch create mode 100644 queue-6.6/jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch create mode 100644 queue-6.6/jfs-fix-uaf-in-dbfreebits.patch create mode 100644 queue-6.6/jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch create mode 100644 queue-6.6/jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch create mode 100644 queue-6.6/ksmbd-add-refcnt-to-ksmbd_conn-struct.patch create mode 100644 queue-6.6/net-atlantic-avoid-warning-about-potential-string-tr.patch create mode 100644 queue-6.6/net-hisilicon-hip04-fix-of-node-leak-in-probe.patch create mode 100644 queue-6.6/net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch create mode 100644 queue-6.6/net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch create mode 100644 queue-6.6/net-mvpp2-increase-size-of-queue_name-buffer.patch create mode 100644 queue-6.6/net-sched-consistently-use-rcu_replace_pointer-in-ta.patch create mode 100644 queue-6.6/net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch create mode 100644 queue-6.6/netpoll-ensure-clean-state-on-setup-failures.patch create mode 100644 queue-6.6/nfp-use-irqf_no_autoen-flag-in-request_irq.patch create mode 100644 queue-6.6/of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch create mode 100644 queue-6.6/perf-fix-event_function_call-locking.patch create mode 100644 queue-6.6/perf-x86-avoid-missing-caller-address-in-stack-trace.patch create mode 100644 queue-6.6/platform-x86-lenovo-ymc-ignore-the-0x0-state.patch create mode 100644 queue-6.6/platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch create mode 100644 queue-6.6/power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch create mode 100644 queue-6.6/powerpc-pseries-use-correct-data-types-from-pseries_.patch create mode 100644 queue-6.6/proc-add-config-param-to-block-forcing-mem-writes.patch create mode 100644 queue-6.6/rcuscale-provide-clear-error-when-async-specified-wi.patch create mode 100644 queue-6.6/scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch create mode 100644 queue-6.6/scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch create mode 100644 queue-6.6/scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch create mode 100644 queue-6.6/scsi-smartpqi-correct-stream-detection.patch create mode 100644 queue-6.6/selftests-nolibc-avoid-passing-null-to-printf-s.patch create mode 100644 queue-6.6/tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch create mode 100644 queue-6.6/tipc-guard-against-string-buffer-overrun.patch create mode 100644 queue-6.6/tools-nolibc-powerpc-limit-stack-protector-workaroun.patch create mode 100644 queue-6.6/tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch create mode 100644 queue-6.6/wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch create mode 100644 queue-6.6/wifi-ath12k-fix-array-out-of-bound-access-in-soc-sta.patch create mode 100644 queue-6.6/wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch create mode 100644 queue-6.6/wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch create mode 100644 queue-6.6/wifi-cfg80211-set-correct-chandef-when-starting-cac.patch create mode 100644 queue-6.6/wifi-iwlwifi-mvm-avoid-null-pointer-dereference.patch create mode 100644 queue-6.6/wifi-iwlwifi-mvm-drop-wrong-sta-selection-in-tx.patch create mode 100644 queue-6.6/wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch create mode 100644 queue-6.6/wifi-iwlwifi-mvm-use-correct-key-iteration.patch create mode 100644 queue-6.6/wifi-mac80211-fix-rcu-list-iterations.patch create mode 100644 queue-6.6/wifi-mt76-mt7915-add-dummy-hw-offload-of-ieee-802.11.patch create mode 100644 queue-6.6/wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch create mode 100644 queue-6.6/wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch create mode 100644 queue-6.6/wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch create mode 100644 queue-6.6/wifi-rtw88-select-want_dev_coredump.patch create mode 100644 queue-6.6/wifi-rtw89-avoid-to-add-interface-to-list-twice-when.patch create mode 100644 queue-6.6/wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch create mode 100644 queue-6.6/x86-ioapic-handle-allocation-failures-gracefully.patch create mode 100644 queue-6.6/x86-kexec-add-efi-config-table-identity-mapping-for-.patch create mode 100644 queue-6.6/x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch create mode 100644 queue-6.6/x86-pkeys-restore-altstack-access-in-sigreturn.patch create mode 100644 queue-6.6/x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch diff --git a/queue-6.6/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch b/queue-6.6/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch new file mode 100644 index 00000000000..8d296ccb3c4 --- /dev/null +++ b/queue-6.6/acpi-cppc-add-support-for-setting-epp-register-in-ff.patch @@ -0,0 +1,74 @@ +From 11e7351b69d6818c268a25e2e9ae95a3b299647e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20240910031524.106387-1-superm1@kernel.org +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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 28217a995f795..7aced0b9bad7c 100644 +--- a/drivers/acpi/cppc_acpi.c ++++ b/drivers/acpi/cppc_acpi.c +@@ -100,6 +100,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 == \ +@@ -1514,9 +1519,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.6/acpi-ec-do-not-release-locks-during-operation-region.patch b/queue-6.6/acpi-ec-do-not-release-locks-during-operation-region.patch new file mode 100644 index 00000000000..23ae012ba5e --- /dev/null +++ b/queue-6.6/acpi-ec-do-not-release-locks-during-operation-region.patch @@ -0,0 +1,166 @@ +From af68c6bb2ade944d797015422080335874b231f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jul 2024 18:26:54 +0200 +Subject: ACPI: EC: Do not release locks during operation region accesses + +From: Rafael J. Wysocki + +[ 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 +Reviewed-by: Hans de Goede +Link: https://patch.msgid.link/12473338.O9o76ZdvQC@rjwysocki.net +Signed-off-by: Sasha Levin +--- + 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 35e22a2af4e4b..115994dfefec1 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.6/acpi-pad-fix-crash-in-exit_round_robin.patch b/queue-6.6/acpi-pad-fix-crash-in-exit_round_robin.patch new file mode 100644 index 00000000000..ab59217d2d1 --- /dev/null +++ b/queue-6.6/acpi-pad-fix-crash-in-exit_round_robin.patch @@ -0,0 +1,96 @@ +From cf90a1b29273f20bb3d982622305a616cea49be6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 23:13:52 +0900 +Subject: ACPI: PAD: fix crash in exit_round_robin() + +From: Seiji Nishikawa + +[ 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 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 : 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 : 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 : lock btr %rax,0x19cf4(%rip) # 0xffffffffc0740620 + +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 +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 +Signed-off-by: Sasha Levin +--- + 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 7a453c5ff303a..71e25c7989762 100644 +--- a/drivers/acpi/acpi_pad.c ++++ b/drivers/acpi/acpi_pad.c +@@ -131,8 +131,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.6/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch b/queue-6.6/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch new file mode 100644 index 00000000000..8a01e83858f --- /dev/null +++ b/queue-6.6/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch @@ -0,0 +1,45 @@ +From 760a64092b81193376e32562762463d326f9d9c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20240907124419.21195-1-hdegoede@redhat.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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 16ab2d9ef67f3..e96afb1622f95 100644 +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -260,6 +260,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.6/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch b/queue-6.6/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch new file mode 100644 index 00000000000..edb611e42bd --- /dev/null +++ b/queue-6.6/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch @@ -0,0 +1,41 @@ +From 2dd1c125dc9fe59450e59bbb6d30a3fe04c51553 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/tencent_4A21A2865B8B0A0D12CAEBEB84708EDDB505@qq.com +[ rjw: Subject and changelog edits ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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.6/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch b/queue-6.6/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch new file mode 100644 index 00000000000..1f86221bf56 --- /dev/null +++ b/queue-6.6/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch @@ -0,0 +1,90 @@ +From f404a978b6dbbfaed8130586e5e42cb24930a215 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Apr 2024 21:50:33 +0200 +Subject: ACPICA: Fix memory leak if acpi_ps_get_next_field() fails + +From: Armin Wolf + +[ 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 +[ rjw: Rename local variable to avoid compiler confusion ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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.6/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch b/queue-6.6/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch new file mode 100644 index 00000000000..e830f59f1a1 --- /dev/null +++ b/queue-6.6/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch @@ -0,0 +1,55 @@ +From 5c618ad33f20add30dca60ab08eb368090cec0d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Apr 2024 20:50:11 +0200 +Subject: ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails + +From: Armin Wolf + +[ 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 +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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.6/acpica-iasl-handle-empty-connection_node.patch b/queue-6.6/acpica-iasl-handle-empty-connection_node.patch new file mode 100644 index 00000000000..87a9a3c18f8 --- /dev/null +++ b/queue-6.6/acpica-iasl-handle-empty-connection_node.patch @@ -0,0 +1,36 @@ +From dfce9578db7b274d427b5db870db8ad1c0e90ee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Aug 2024 23:33:44 +0200 +Subject: ACPICA: iasl: handle empty connection_node + +From: Aleksandrs Vinarskis + +[ Upstream commit a0a2459b79414584af6c46dd8c6f866d8f1aa421 ] + +ACPICA commit 6c551e2c9487067d4b085333e7fe97e965a11625 + +Link: https://github.com/acpica/acpica/commit/6c551e2c +Signed-off-by: Aleksandrs Vinarskis +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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.6/alsa-asihpi-fix-potential-oob-array-access.patch b/queue-6.6/alsa-asihpi-fix-potential-oob-array-access.patch new file mode 100644 index 00000000000..d5093d20c2e --- /dev/null +++ b/queue-6.6/alsa-asihpi-fix-potential-oob-array-access.patch @@ -0,0 +1,39 @@ +From a0bc4c6478c2d29d52108951cb9b0db6c8b6da32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 11:14:42 +0200 +Subject: ALSA: asihpi: Fix potential OOB array access + +From: Takashi Iwai + +[ 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 +Signed-off-by: Sasha Levin +--- + 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.6/alsa-hdsp-break-infinite-midi-input-flush-loop.patch b/queue-6.6/alsa-hdsp-break-infinite-midi-input-flush-loop.patch new file mode 100644 index 00000000000..f231794c9da --- /dev/null +++ b/queue-6.6/alsa-hdsp-break-infinite-midi-input-flush-loop.patch @@ -0,0 +1,60 @@ +From e7fd9d012e95a4ae2e77fed0a0f6592e1c199217 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 11:15:12 +0200 +Subject: ALSA: hdsp: Break infinite MIDI input flush loop + +From: Takashi Iwai + +[ 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 +Signed-off-by: Sasha Levin +--- + 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.6/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch b/queue-6.6/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch new file mode 100644 index 00000000000..c29089432fb --- /dev/null +++ b/queue-6.6/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch @@ -0,0 +1,140 @@ +From c65e29c2f2ba48d416183313808e7c67a5f0bb68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Aug 2024 14:46:50 +0200 +Subject: ALSA: usb-audio: Add input value sanity checks for standard types + +From: Takashi Iwai + +[ 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 +Signed-off-by: Sasha Levin +--- + 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.6/alsa-usb-audio-add-logitech-audio-profile-quirk.patch b/queue-6.6/alsa-usb-audio-add-logitech-audio-profile-quirk.patch new file mode 100644 index 00000000000..1706792127d --- /dev/null +++ b/queue-6.6/alsa-usb-audio-add-logitech-audio-profile-quirk.patch @@ -0,0 +1,40 @@ +From 022dbc16ee170190d272127e66d1c8ef52152069 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Sep 2024 15:26:28 +0000 +Subject: ALSA: usb-audio: Add logitech Audio profile quirk + +From: Joshua Pius + +[ Upstream commit a51c925c11d7b855167e64b63eb4378e5adfc11d ] + +Specify shortnames for the following Logitech Devices: Rally bar, Rally +bar mini, Tap, MeetUp and Huddle. + +Signed-off-by: Joshua Pius +Link: https://patch.msgid.link/20240912152635.1859737-1-joshuapius@google.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/card.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/usb/card.c b/sound/usb/card.c +index 7c98cc831b8d9..753fb47d25913 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.6/alsa-usb-audio-define-macros-for-quirk-table-entries.patch b/queue-6.6/alsa-usb-audio-define-macros-for-quirk-table-entries.patch new file mode 100644 index 00000000000..8ad1411bb09 --- /dev/null +++ b/queue-6.6/alsa-usb-audio-define-macros-for-quirk-table-entries.patch @@ -0,0 +1,111 @@ +From 08800022a8f197abf4f0e3ae18ea87176c829bca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Aug 2024 15:48:41 +0200 +Subject: ALSA: usb-audio: Define macros for quirk table entries + +From: Takashi Iwai + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 d2aa97a5c438c..a0063caa769c5 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.6/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch b/queue-6.6/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch new file mode 100644 index 00000000000..f425690d93d --- /dev/null +++ b/queue-6.6/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch @@ -0,0 +1,4000 @@ +From 43a14fc48cfd80a581987d234732f40f384824fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Aug 2024 15:48:42 +0200 +Subject: ALSA: usb-audio: Replace complex quirk lines with macros + +From: Takashi Iwai + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 a0063caa769c5..75cde5779f38d 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 + * 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 + */ + 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 */ + 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, + .channels = 4, + .iface = 2, +@@ -3113,9 +2351,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, + .channels = 4, + .iface = 3, +@@ -3136,36 +2372,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, +@@ -3186,9 +2411,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3196,20 +2419,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, +@@ -3230,9 +2446,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, +@@ -3252,13 +2466,8 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 4, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_MIDI(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3267,17 +2476,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, +@@ -3293,9 +2498,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, +@@ -3309,9 +2512,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 16000 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3320,18 +2521,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, +@@ -3350,9 +2544,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3365,28 +2557,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 + } + } + }, +@@ -3400,18 +2576,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) + } + }, + +@@ -3427,24 +2601,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, +@@ -3463,9 +2626,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3478,19 +2639,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, +@@ -3509,29 +2663,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, +@@ -3552,9 +2697,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, +@@ -3575,9 +2718,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3589,14 +2730,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, +@@ -3613,9 +2750,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, +@@ -3633,9 +2768,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3678,14 +2811,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, +@@ -3702,9 +2831,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, +@@ -3722,9 +2849,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3735,14 +2860,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, +@@ -3759,9 +2880,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, +@@ -3779,9 +2898,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3792,14 +2909,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, +@@ -3816,9 +2929,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, +@@ -3836,9 +2947,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3850,14 +2959,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, +@@ -3874,9 +2979,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, +@@ -3894,9 +2997,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3907,14 +3008,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, +@@ -3935,9 +3032,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, +@@ -3959,9 +3054,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3973,14 +3066,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, +@@ -3997,9 +3086,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, +@@ -4017,9 +3104,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4037,20 +3122,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, +@@ -4065,9 +3143,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 48000, + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4085,20 +3161,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, +@@ -4113,9 +3182,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 48000, + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4125,14 +3192,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, +@@ -4151,9 +3214,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, +@@ -4173,9 +3234,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4185,14 +3244,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, +@@ -4211,9 +3266,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, +@@ -4231,9 +3284,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4245,14 +3296,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, +@@ -4272,9 +3319,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, +@@ -4294,9 +3339,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4307,14 +3350,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, +@@ -4331,9 +3370,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, +@@ -4351,9 +3388,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4364,28 +3399,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 + } + } + }, +@@ -4394,21 +3416,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, +@@ -4428,9 +3443,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, +@@ -4449,9 +3462,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4460,21 +3471,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, +@@ -4494,9 +3498,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, +@@ -4515,9 +3517,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4526,21 +3526,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, +@@ -4561,9 +3554,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, +@@ -4583,9 +3574,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4594,27 +3583,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.6/alsa-usb-audio-support-multiple-control-interfaces.patch b/queue-6.6/alsa-usb-audio-support-multiple-control-interfaces.patch new file mode 100644 index 00000000000..811d448a0e0 --- /dev/null +++ b/queue-6.6/alsa-usb-audio-support-multiple-control-interfaces.patch @@ -0,0 +1,659 @@ +From 4e61357fcd14afe57ede4e02ad249cf7763f3afb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Aug 2024 17:29:56 -0700 +Subject: ALSA: usb-audio: Support multiple control interfaces + +From: Karol Kosik + +[ 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 +Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + 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 1b2edc0fd2e99..7c98cc831b8d9 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 a676ad093d189..6f0693c428b0b 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) { +@@ -272,7 +284,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, +@@ -285,7 +297,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); +@@ -299,7 +311,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; +@@ -327,7 +339,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + /* Skip setting clock selector again for some devices */ + if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR) + 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, +@@ -355,7 +367,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; + +@@ -369,7 +381,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), +@@ -469,11 +481,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", +@@ -502,8 +516,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; +@@ -522,7 +538,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 c8d48566e1759..2323504339328 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.6/asoc-codecs-wsa883x-handle-reading-version-failure.patch b/queue-6.6/asoc-codecs-wsa883x-handle-reading-version-failure.patch new file mode 100644 index 00000000000..086fe0c38b5 --- /dev/null +++ b/queue-6.6/asoc-codecs-wsa883x-handle-reading-version-failure.patch @@ -0,0 +1,72 @@ +From 52cb7b4c1baa14f1f81e7d2d4aac61a6af4ad521 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jul 2024 15:52:31 +0200 +Subject: ASoC: codecs: wsa883x: Handle reading version failure + +From: Krzysztof Kozlowski + +[ 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 +Link: https://patch.msgid.link/20240710-asoc-wsa88xx-version-v1-2-f1c54966ccde@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + 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.6/ata-pata_serverworks-do-not-use-the-term-blacklist.patch b/queue-6.6/ata-pata_serverworks-do-not-use-the-term-blacklist.patch new file mode 100644 index 00000000000..a201f4a543e --- /dev/null +++ b/queue-6.6/ata-pata_serverworks-do-not-use-the-term-blacklist.patch @@ -0,0 +1,65 @@ +From 42d39bc4b62b250f748f6914e0a9594fb0ba98c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 10:58:36 +0900 +Subject: ata: pata_serverworks: Do not use the term blacklist + +From: Damien Le Moal + +[ 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 +Reviewed-by: Niklas Cassel +Reviewed-by: Igor Pylypiv +Signed-off-by: Sasha Levin +--- + 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.6/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch b/queue-6.6/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch new file mode 100644 index 00000000000..c878029b7b3 --- /dev/null +++ b/queue-6.6/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch @@ -0,0 +1,61 @@ +From 09833f560d98999c8ceed4d4b5950dce7aabc8de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 11:14:11 +0900 +Subject: ata: sata_sil: Rename sil_blacklist to sil_quirks + +From: Damien Le Moal + +[ 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 +Reviewed-by: Niklas Cassel +Reviewed-by: Igor Pylypiv +Signed-off-by: Sasha Levin +--- + 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.6/blk_iocost-fix-more-out-of-bound-shifts.patch b/queue-6.6/blk_iocost-fix-more-out-of-bound-shifts.patch new file mode 100644 index 00000000000..a595054869a --- /dev/null +++ b/queue-6.6/blk_iocost-fix-more-out-of-bound-shifts.patch @@ -0,0 +1,80 @@ +From 1678be78da26f84997ba905bff4e19e53b5fff5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Aug 2024 08:41:36 -0700 +Subject: blk_iocost: fix more out of bound shifts + +From: Konstantin Ovsepian + +[ 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: + +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 +Signed-off-by: Konstantin Ovsepian +Acked-by: Tejun Heo +Link: https://lore.kernel.org/r/20240822154137.2627818-1-ovs@ovs.to +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + 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 0dca77591d66c..c3cb9c20b306c 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.6/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch b/queue-6.6/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch new file mode 100644 index 00000000000..510e9c70ddd --- /dev/null +++ b/queue-6.6/bluetooth-btrtl-set-msft-ext-address-filter-quirk-fo.patch @@ -0,0 +1,42 @@ +From 52c471aac7721d9de99333e7e53ad574cea932f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Aug 2024 16:40:05 +0800 +Subject: Bluetooth: btrtl: Set msft ext address filter quirk for RTL8852B + +From: Hilda Wu + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btrtl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c +index 277d039ecbb42..1e7c1f9db9e4b 100644 +--- a/drivers/bluetooth/btrtl.c ++++ b/drivers/bluetooth/btrtl.c +@@ -1285,6 +1285,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.6/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch b/queue-6.6/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch new file mode 100644 index 00000000000..1c6dcc6b073 --- /dev/null +++ b/queue-6.6/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch @@ -0,0 +1,67 @@ +From 9c819c5325ee878b8ab646d69555e84d41a9d30c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Aug 2024 16:58:22 +0800 +Subject: Bluetooth: btusb: Add Realtek RTL8852C support ID 0x0489:0xe122 + +From: Hilda Wu + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index 0a58106207b0c..bc53da383f855 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -537,6 +537,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.6/bnxt_en-extend-maximum-length-of-version-string-by-1.patch b/queue-6.6/bnxt_en-extend-maximum-length-of-version-string-by-1.patch new file mode 100644 index 00000000000..f5d76cebb92 --- /dev/null +++ b/queue-6.6/bnxt_en-extend-maximum-length-of-version-string-by-1.patch @@ -0,0 +1,42 @@ +From 6a46e28ed50529057aa1a314f8b5ac61fd129334 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 15:32:55 +0100 +Subject: bnxt_en: Extend maximum length of version string by 1 byte + +From: Simon Horman + +[ 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 +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20240813-bnxt-str-v2-1-872050a157e7@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 3c36dd8051485..2e7ddbca9d53b 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -3021,7 +3021,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.6/bpf-make-the-pointer-returned-by-iter-next-method-va.patch b/queue-6.6/bpf-make-the-pointer-returned-by-iter-next-method-va.patch new file mode 100644 index 00000000000..e77bd64ed1a --- /dev/null +++ b/queue-6.6/bpf-make-the-pointer-returned-by-iter-next-method-va.patch @@ -0,0 +1,108 @@ +From 8c27780ba784b95663462e4763f7a9145fc62c7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Aug 2024 21:11:17 +0100 +Subject: bpf: Make the pointer returned by iter next method valid + +From: Juntong Deng + +[ 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 +Link: https://lore.kernel.org/r/AM6PR03MB584869F8B448EA1C87B7CDA399962@AM6PR03MB5848.eurprd03.prod.outlook.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + 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 834394faf2af3..3032a464d31bb 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -7846,6 +7846,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. +@@ -7930,12 +7939,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) { +@@ -7963,7 +7970,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) +@@ -11995,6 +12002,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.6/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch b/queue-6.6/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch new file mode 100644 index 00000000000..7ef4f54332b --- /dev/null +++ b/queue-6.6/bpftool-fix-undefined-behavior-caused-by-shifting-in.patch @@ -0,0 +1,55 @@ +From 99a96f828df7b2d1bddd877c9da5a673043b056d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Andrii Nakryiko +Acked-by: Quentin Monnet +Link: https://lore.kernel.org/bpf/20240908140009.3149781-1-visitorckw@gmail.com +Signed-off-by: Sasha Levin +--- + 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 66a8ce8ae0127..fd54ff436493f 100644 +--- a/tools/bpf/bpftool/net.c ++++ b/tools/bpf/bpftool/net.c +@@ -480,9 +480,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(""); + } +@@ -491,9 +491,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.6/bpftool-fix-undefined-behavior-in-qsort-null-0.patch b/queue-6.6/bpftool-fix-undefined-behavior-in-qsort-null-0.patch new file mode 100644 index 00000000000..37e32543090 --- /dev/null +++ b/queue-6.6/bpftool-fix-undefined-behavior-in-qsort-null-0.patch @@ -0,0 +1,57 @@ +From 9cf04f18ddc81958246919b7723c0c1b7f8301e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Sep 2024 23:02:07 +0800 +Subject: bpftool: Fix undefined behavior in qsort(NULL, 0, ...) + +From: Kuan-Wei Chiu + +[ 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 +Signed-off-by: Andrii Nakryiko +Reviewed-by: Quentin Monnet +Link: https://lore.kernel.org/bpf/20240910150207.3179306-1-visitorckw@gmail.com +Signed-off-by: Sasha Levin +--- + 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 fd54ff436493f..28e9417a5c2e3 100644 +--- a/tools/bpf/bpftool/net.c ++++ b/tools/bpf/bpftool/net.c +@@ -819,6 +819,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.6/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch b/queue-6.6/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch new file mode 100644 index 00000000000..2d9e94d2a09 --- /dev/null +++ b/queue-6.6/can-netlink-avoid-call-to-do_set_data_bittiming-call.patch @@ -0,0 +1,173 @@ +From b65cbc663d5853808447924959a786192b21768c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20240808164224.213522-1-stefan.maetje@esd.eu +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + 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.6/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch b/queue-6.6/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch new file mode 100644 index 00000000000..4789860566f --- /dev/null +++ b/queue-6.6/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch @@ -0,0 +1,71 @@ +From 3e3f06157524e8bf35904f76100b5681f47f4da7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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ý + +[ 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ý +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + 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 9cb00ebe9ac6d..01149e47e1a72 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.6/coredump-standartize-and-fix-logging.patch b/queue-6.6/coredump-standartize-and-fix-logging.patch new file mode 100644 index 00000000000..2aed824d918 --- /dev/null +++ b/queue-6.6/coredump-standartize-and-fix-logging.patch @@ -0,0 +1,178 @@ +From b7acd4bcef84951322c7d77d02c69c29384e4d61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Jul 2024 11:27:24 -0700 +Subject: coredump: Standartize and fix logging + +From: Roman Kisel + +[ 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 +Tested-by: Allen Pais +Link: https://lore.kernel.org/r/20240718182743.1959160-2-romank@linux.microsoft.com +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + 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 9d235fa14ab98..9846b4d06c3dd 100644 +--- a/fs/coredump.c ++++ b/fs/coredump.c +@@ -583,8 +583,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; + } + +@@ -604,27 +603,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++) +@@ -641,8 +634,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 { +@@ -655,10 +647,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; + } + +@@ -727,13 +717,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)) +@@ -754,7 +744,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)) +@@ -941,11 +931,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 d3eba43601508..f897de8ccea8c 100644 +--- a/include/linux/coredump.h ++++ b/include/linux/coredump.h +@@ -41,8 +41,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.6/crypto-octeontx-fix-authenc-setkey.patch b/queue-6.6/crypto-octeontx-fix-authenc-setkey.patch new file mode 100644 index 00000000000..fe17e15cd31 --- /dev/null +++ b/queue-6.6/crypto-octeontx-fix-authenc-setkey.patch @@ -0,0 +1,408 @@ +From 034dde6aa1016a5d75d830985e9007d7ab4e9c41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 12:13:23 +0800 +Subject: crypto: octeontx - Fix authenc setkey + +From: Herbert Xu + +[ 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 +Signed-off-by: Sasha Levin +--- + .../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 1c2c870e887aa..f64b72398eced 100644 +--- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c ++++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #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; +@@ -515,44 +516,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; + } +@@ -608,8 +626,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); + } + +@@ -705,7 +722,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; +@@ -713,22 +730,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: +@@ -738,55 +752,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); + +@@ -804,7 +816,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; + +@@ -812,25 +824,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; + } + +@@ -838,57 +834,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; + } +@@ -897,36 +851,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.6/crypto-octeontx2-fix-authenc-setkey.patch b/queue-6.6/crypto-octeontx2-fix-authenc-setkey.patch new file mode 100644 index 00000000000..98451f04a9f --- /dev/null +++ b/queue-6.6/crypto-octeontx2-fix-authenc-setkey.patch @@ -0,0 +1,394 @@ +From b770435ecc3f2fc67438e8d13ba7ea3042789411 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 12:36:19 +0800 +Subject: crypto: octeontx2 - Fix authenc setkey + +From: Herbert Xu + +[ 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 +Signed-off-by: Sasha Levin +--- + .../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 e27ddd3c4e558..4385d3df52b4d 100644 +--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c ++++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include "otx2_cptvf.h" +@@ -54,6 +53,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; +@@ -580,40 +581,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) { +@@ -686,8 +703,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) { +@@ -760,7 +776,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; +@@ -768,22 +784,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: +@@ -793,55 +806,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); + +@@ -859,7 +871,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; + +@@ -867,25 +879,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; + } + +@@ -893,87 +889,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.6/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch b/queue-6.6/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch new file mode 100644 index 00000000000..5d429c73b8a --- /dev/null +++ b/queue-6.6/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch @@ -0,0 +1,249 @@ +From d2b1471e39dac57118c940e9b9d08f6cde68b3f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 14:58:35 +0800 +Subject: crypto: simd - Do not call crypto_alloc_tfm during registration + +From: Herbert Xu + +[ 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 +Signed-off-by: Sasha Levin +--- + 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.6/crypto-x86-sha256-add-parentheses-around-macros-sing.patch b/queue-6.6/crypto-x86-sha256-add-parentheses-around-macros-sing.patch new file mode 100644 index 00000000000..8c5f416cc2e --- /dev/null +++ b/queue-6.6/crypto-x86-sha256-add-parentheses-around-macros-sing.patch @@ -0,0 +1,92 @@ +From 4167500d82523271367302466f0a1ed161f3eb90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 21:48:02 -0700 +Subject: crypto: x86/sha256 - Add parentheses around macros' single arguments + +From: Fangrui Song + +[ 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 +Reviewed-by: Jan Beulich +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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.6/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch b/queue-6.6/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch new file mode 100644 index 00000000000..bacb01bcd98 --- /dev/null +++ b/queue-6.6/drivers-perf-arm_spe-use-perf_allow_kernel-for-permi.patch @@ -0,0 +1,115 @@ +From 7269f5311f2fb6cdf3bdb53e22be48f5fa9c0acb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Aug 2024 15:51:12 +0100 +Subject: drivers/perf: arm_spe: Use perf_allow_kernel() for permissions + +From: James Clark + +[ 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 +Signed-off-by: James Clark +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 +Signed-off-by: Sasha Levin +--- + 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 d2b0cbf0e0c41..2bec2e3af0bd6 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; + } + +@@ -767,9 +767,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 95d4118ee4a91..7a5563ffe61b5 100644 +--- a/include/linux/perf_event.h ++++ b/include/linux/perf_event.h +@@ -1599,13 +1599,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 4d0abdace4e7c..d40809bdf4b30 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -13330,6 +13330,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.6/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch b/queue-6.6/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch new file mode 100644 index 00000000000..af9462f9cea --- /dev/null +++ b/queue-6.6/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch @@ -0,0 +1,54 @@ +From de8f58eb2956b1bf822f21ea7e619e53e0f2b996 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Co-developed-by: Alex Hung +Signed-off-by: Alex Hung +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 fa9f53b310793..d1329f20b7bd4 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 +@@ -1281,7 +1281,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.6/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch b/queue-6.6/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch new file mode 100644 index 00000000000..e9077c75628 --- /dev/null +++ b/queue-6.6/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch @@ -0,0 +1,52 @@ +From f387763f7b8015631667f53887014aa73baaa303 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 50e643bfdfbad..0b2eb2a6c8e14 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -3797,7 +3797,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.6/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch b/queue-6.6/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch new file mode 100644 index 00000000000..64f054e1f12 --- /dev/null +++ b/queue-6.6/drm-amd-display-avoid-overflow-assignment-in-link_dp.patch @@ -0,0 +1,71 @@ +From 18543a80c0ca2838aa5e17d45ab80262c2b52e71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Jul 2024 09:17:56 -0600 +Subject: drm/amd/display: Avoid overflow assignment in link_dp_cts + +From: Alex Hung + +[ 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 +Reviewed-by: Wenjing Liu +Tested-by: Daniel Wheeler +Signed-off-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 83719f5bea495..8df52f9ba0b7c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +@@ -721,7 +721,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 fe4282771cd07..8a97d96f7d8bb 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 +@@ -849,7 +849,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.6/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch b/queue-6.6/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch new file mode 100644 index 00000000000..e98137131fa --- /dev/null +++ b/queue-6.6/drm-amd-display-check-link_res-hpo_dp_link_enc-befor.patch @@ -0,0 +1,54 @@ +From 7f9dfc71e72f01f2d53185ddec3909bec9c71aed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../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.6/drm-amd-display-check-null-pointers-before-using-dc-.patch b/queue-6.6/drm-amd-display-check-null-pointers-before-using-dc-.patch new file mode 100644 index 00000000000..b161811f784 --- /dev/null +++ b/queue-6.6/drm-amd-display-check-null-pointers-before-using-dc-.patch @@ -0,0 +1,46 @@ +From 088d266f3ca7ddf977d2fccf318ffe0c3b96808a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 15:29:09 -0600 +Subject: drm/amd/display: Check null pointers before using dc->clk_mgr + +From: Alex Hung + +[ 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 +Signed-off-by: Alex Hung +Signed-off-by: Tom Chung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 0b2eb2a6c8e14..a7a6f6c5c7655 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -4716,7 +4716,8 @@ void dc_allow_idle_optimizations(struct dc *dc, bool allow) + 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.6/drm-amd-display-check-stream-before-comparing-them.patch b/queue-6.6/drm-amd-display-check-stream-before-comparing-them.patch new file mode 100644 index 00000000000..7e6a49865a7 --- /dev/null +++ b/queue-6.6/drm-amd-display-check-stream-before-comparing-them.patch @@ -0,0 +1,41 @@ +From d296ffb31209cb7023dbc56e8b024bd5dbbf1fb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jun 2024 20:05:14 -0600 +Subject: drm/amd/display: Check stream before comparing them + +From: Alex Hung + +[ 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 +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 4b34bc9d4e4be..99fcd39bb15e0 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -2154,6 +2154,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.6/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch b/queue-6.6/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch new file mode 100644 index 00000000000..17aebc404d5 --- /dev/null +++ b/queue-6.6/drm-amd-display-fix-double-free-issue-during-amdgpu-.patch @@ -0,0 +1,79 @@ +From d66a141968467ded9f122837d8a1cd40789ebf5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Aug 2024 18:45:22 -0400 +Subject: drm/amd/display: fix double free issue during amdgpu module unload + +From: Tim Huang + +[ 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] +[ 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] + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Tim Huang +Reviewed-by: Roman Li +Signed-off-by: Roman Li +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 33bb96f770b86..eb7c9f226af5c 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -403,7 +403,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.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch b/queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch new file mode 100644 index 00000000000..f0f0ca995fc --- /dev/null +++ b/queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch @@ -0,0 +1,54 @@ +From fd36ae14bf007a7802687539297705ad925ff56b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 e0b1fc92ed186..62c02adae7e76 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 +@@ -178,6 +178,8 @@ bool cm3_helper_translate_curve_to_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.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch b/queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch new file mode 100644 index 00000000000..41f87188daf --- /dev/null +++ b/queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch @@ -0,0 +1,55 @@ +From 93d0309cb1e6e1b332db85fb722ed9d11deeecd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 e0df9b0065f9c..e0b1fc92ed186 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 +@@ -355,6 +355,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.6/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch b/queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch new file mode 100644 index 00000000000..b3eee67a1b3 --- /dev/null +++ b/queue-6.6/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch @@ -0,0 +1,55 @@ +From 26b70eccfda666d96f2fd7e4d149c8d37274864f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 c0372aa4ec838..684e30f9cf898 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 +@@ -571,6 +571,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.6/drm-amd-display-handle-null-stream_status-in-planes_.patch b/queue-6.6/drm-amd-display-handle-null-stream_status-in-planes_.patch new file mode 100644 index 00000000000..82565662bf6 --- /dev/null +++ b/queue-6.6/drm-amd-display-handle-null-stream_status-in-planes_.patch @@ -0,0 +1,52 @@ +From 382d611b9ce01f210b6282012e5ec0bd4727ce76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 733e445331ea5..4b34bc9d4e4be 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -2877,8 +2877,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.6/drm-amd-display-initialize-get_bytes_per_element-s-d.patch b/queue-6.6/drm-amd-display-initialize-get_bytes_per_element-s-d.patch new file mode 100644 index 00000000000..bf238abe487 --- /dev/null +++ b/queue-6.6/drm-amd-display-initialize-get_bytes_per_element-s-d.patch @@ -0,0 +1,55 @@ +From 200e4e586515e42bd79bae0e3cb5c35cb1d5dad0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Aurabindo Pillai +Tested-by: Daniel Wheeler +Signed-off-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../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.6/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch b/queue-6.6/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch new file mode 100644 index 00000000000..96371924626 --- /dev/null +++ b/queue-6.6/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch @@ -0,0 +1,36 @@ +From 7f8f66efc50c2bc6daecfc962c87de0d23c9b84d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ Upstream commit 186fb12e7a7b038c2710ceb2fb74068f1b5d55a4 ] + +This resolves the dereference null return value warning +reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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.6/drm-amdgpu-add-raven1-gfxoff-quirk.patch b/queue-6.6/drm-amdgpu-add-raven1-gfxoff-quirk.patch new file mode 100644 index 00000000000..51e2e85e42b --- /dev/null +++ b/queue-6.6/drm-amdgpu-add-raven1-gfxoff-quirk.patch @@ -0,0 +1,35 @@ +From 90507d2289abbd50a8be6288d9001d63b4116338 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Aug 2024 15:25:54 +0800 +Subject: drm/amdgpu: add raven1 gfxoff quirk + +From: Peng Liu + +[ Upstream commit 0126c0ae11e8b52ecfde9d1b174ee2f32d6c3a5d ] + +Fix screen corruption with openkylin. + +Link: https://bbs.openkylin.top/t/topic/171497 +Signed-off-by: Peng Liu +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 8168836a08d2e..c28e7ff6ede26 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.6/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch b/queue-6.6/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch new file mode 100644 index 00000000000..3bc049d38f8 --- /dev/null +++ b/queue-6.6/drm-amdgpu-block-mmr_read-ioctl-in-reset.patch @@ -0,0 +1,111 @@ +From 1884e683f32b46fd2925e4b2197ee5b448dedf42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 13:40:23 -0400 +Subject: drm/amdgpu: Block MMR_READ IOCTL in reset + +From: Victor Skvortsov + +[ Upstream commit 9e823f307074c0f82b5f6044943b0086e3079bed ] + +Register access from userspace should be blocked until +reset is complete. + +Signed-off-by: Victor Skvortsov +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 58dab4f73a9a2..5797055b1148f 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) +@@ -722,6 +723,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 >> +@@ -731,24 +733,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); +@@ -760,13 +775,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.6/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch b/queue-6.6/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch new file mode 100644 index 00000000000..a6fa811b452 --- /dev/null +++ b/queue-6.6/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch @@ -0,0 +1,49 @@ +From 001e393c6b9935df56ca902bcebeca6a38fedbf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 e361dc37a0890..7abcd618e70bd 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.6/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch b/queue-6.6/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch new file mode 100644 index 00000000000..fa3cba38a69 --- /dev/null +++ b/queue-6.6/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch @@ -0,0 +1,38 @@ +From 13a5bd2416a66454503e4d2cead480c4443af849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Aug 2024 15:27:08 +0800 +Subject: drm/amdgpu: enable gfxoff quirk on HP 705G4 + +From: Peng Liu + +[ 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 +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 c28e7ff6ede26..00e693c47f3cc 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.6/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch b/queue-6.6/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch new file mode 100644 index 00000000000..a55e6600353 --- /dev/null +++ b/queue-6.6/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch @@ -0,0 +1,72 @@ +From 31587798e3e5a5e5d93c058e0b9c8685b0e386c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 10:38:37 +0800 +Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_gfx + +From: Tim Huang + +[ Upstream commit c0277b9d7c2ee9ee5dbc948548984f0fbb861301 ] + +This resolves the unchecded return value warning reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 0ca51df46cc0d..e7b053898f9e9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -793,8 +793,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) +@@ -938,7 +941,10 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg) + 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) +@@ -1004,7 +1010,10 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) + } + + 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) +@@ -1040,6 +1049,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) + + 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.6/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.6/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch new file mode 100644 index 00000000000..96777c462e2 --- /dev/null +++ b/queue-6.6/drm-amdgpu-gfx10-use-rlc-safe-mode-for-soft-recovery.patch @@ -0,0 +1,35 @@ +From 5d481a2584f90c79ce0c428cb7434e1f76e633ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jul 2024 18:20:34 -0400 +Subject: drm/amdgpu/gfx10: use rlc safe mode for soft recovery + +From: Alex Deucher + +[ Upstream commit ead60e9c4e29c8574cae1be4fe3af1d9a978fb0f ] + +Protect the MMIO access with safe mode. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 cd594b92c6129..53c99bc6abb33 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -8748,7 +8748,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.6/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.6/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch new file mode 100644 index 00000000000..36c01a1e0ea --- /dev/null +++ b/queue-6.6/drm-amdgpu-gfx11-use-rlc-safe-mode-for-soft-recovery.patch @@ -0,0 +1,35 @@ +From 1159fe14e1a53b4abb916ba2e011af9bc7397298 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jul 2024 18:20:23 -0400 +Subject: drm/amdgpu/gfx11: use rlc safe mode for soft recovery + +From: Alex Deucher + +[ Upstream commit 3f2d35c325534c1b7ac5072173f0dc7ca969dec2 ] + +Protect the MMIO access with safe mode. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 c813cd7b015e1..54ec9b32562c2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -5701,7 +5701,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.6/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch b/queue-6.6/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch new file mode 100644 index 00000000000..0dd745e37e7 --- /dev/null +++ b/queue-6.6/drm-amdgpu-gfx9-use-rlc-safe-mode-for-soft-recovery.patch @@ -0,0 +1,35 @@ +From bb37bbc130e19cdff2d8441ee1a3902c015ad285 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jul 2024 18:20:57 -0400 +Subject: drm/amdgpu/gfx9: use rlc safe mode for soft recovery + +From: Alex Deucher + +[ Upstream commit 3ec2ad7c34c412bd9264cd1ff235d0812be90e82 ] + +Protect the MMIO access with safe mode. + +Acked-by: Vitaly Prosyak +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 00e693c47f3cc..895060f6948f3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -5709,7 +5709,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.6/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch b/queue-6.6/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch new file mode 100644 index 00000000000..b3a840f4eff --- /dev/null +++ b/queue-6.6/drm-amdkfd-amdkfd_free_gtt_mem-clear-the-correct-poi.patch @@ -0,0 +1,165 @@ +From 632320db15f04fc72eac7c6fc60fc04eb3d2eeed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Felix Kuehling +Acked-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 25d5fda5b243e..af6c6d89e63af 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +@@ -335,15 +335,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 db5b1c6beba75..3134e6ad81d1d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +@@ -221,7 +221,7 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, + 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 9d10530283705..19d46be639429 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +@@ -417,7 +417,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 0c94bdfadaabf..9d0b0bf70ad1e 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c +@@ -838,7 +838,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", +@@ -856,7 +856,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 60d98301ef041..4d9a406925e18 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -2610,7 +2610,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 447829c22295c..4c3f379803117 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 d98e45aec76b4..43f520b379670 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c +@@ -1047,7 +1047,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 8aca92624a77e..dbc75ca84375a 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -199,9 +199,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.6/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch b/queue-6.6/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch new file mode 100644 index 00000000000..5d1c2ff19ba --- /dev/null +++ b/queue-6.6/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch @@ -0,0 +1,35 @@ +From 67e09898b6d4ecf59dee0830cdf7f2b33d2571a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Sep 2024 11:29:55 +0800 +Subject: drm/amdkfd: Fix resource leak in criu restore queue + +From: Jesse Zhang + +[ 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 +Reviewed-by: Tim Huang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 dbc75ca84375a..0583af4e84fa3 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -982,6 +982,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.6/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch b/queue-6.6/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch new file mode 100644 index 00000000000..ab101d492a4 --- /dev/null +++ b/queue-6.6/drm-msm-adreno-assign-msm_gpu-pdev-earlier-to-avoid-.patch @@ -0,0 +1,61 @@ +From 194b1aec11f044c65fc2d025ed15d887ec4e3af3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jul 2024 13:15:40 +0200 +Subject: drm/msm/adreno: Assign msm_gpu->pdev earlier to avoid nullptrs + +From: Konrad Dybcio + +[ 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 +Patchwork: https://patchwork.freedesktop.org/patch/602742/ +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + 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 4127e2762dcd1..a2df8bd7aa940 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +@@ -1071,6 +1071,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 5c10b559a5957..5a7541597d0ce 100644 +--- a/drivers/gpu/drm/msm/msm_gpu.c ++++ b/drivers/gpu/drm/msm/msm_gpu.c +@@ -927,7 +927,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.6/drm-printer-allow-null-data-in-devcoredump-printer.patch b/queue-6.6/drm-printer-allow-null-data-in-devcoredump-printer.patch new file mode 100644 index 00000000000..95fd3168cd4 --- /dev/null +++ b/queue-6.6/drm-printer-allow-null-data-in-devcoredump-printer.patch @@ -0,0 +1,144 @@ +From a1c3119744b86287d22ef538a4b7db1ef48c0a30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 08:41:17 -0700 +Subject: drm/printer: Allow NULL data in devcoredump printer + +From: Matthew Brost + +[ 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 +Acked-by: Maarten Lankhorst +Signed-off-by: Matthew Brost +Reviewed-by: Jonathan Cavitt +Link: https://patchwork.freedesktop.org/patch/msgid/20240801154118.2547543-3-matthew.brost@intel.com +Signed-off-by: Sasha Levin +--- + 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 5b93c11895bb1..aab76334083e8 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 a93a387f8a1a1..2ad9c9f9e90ff 100644 +--- a/include/drm/drm_print.h ++++ b/include/drm/drm_print.h +@@ -122,7 +122,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 + */ +@@ -167,6 +168,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.6/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch b/queue-6.6/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch new file mode 100644 index 00000000000..27908a6e00a --- /dev/null +++ b/queue-6.6/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch @@ -0,0 +1,140 @@ +From 9508c4ab9c539686912b66c47aa594d79aec4a85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + 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 cfeca2694d5f9..b63b6b4e9b281 100644 +--- a/drivers/gpu/drm/radeon/r100.c ++++ b/drivers/gpu/drm/radeon/r100.c +@@ -1015,45 +1015,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.6/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch b/queue-6.6/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch new file mode 100644 index 00000000000..7f65f694642 --- /dev/null +++ b/queue-6.6/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch @@ -0,0 +1,254 @@ +From 5f85e52cb113329aedbf17b2c7a0d63800105e92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Acked-by: Raphaël Gallais-Pou +Link: https://patchwork.freedesktop.org/patch/msgid/20240216125040.8968-1-e.orlova@ispras.ru +Signed-off-by: Raphael Gallais-Pou +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + #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 + #include + #include ++#include + + #include